何时在$ this上使用self?

时间:2020-03-06 14:54:35  来源:igfitidea点击:

在PHP 5中,使用self$ this有什么区别?

什么时候合适?

解决方案

根据http://www.php.net/manual/zh-CN/language.oop5.static.php,没有$ self。只有$ this可以引用该类的当前实例(对象),而self可以用来引用一个类的静态成员。对象实例和类之间的区别在这里发挥了作用。

Use $this to refer to the current
  object. Use self to refer to the
  current class. In other words, use
  $this->member for non-static members,
  use self::$member for static members.

这是非静态和静态成员变量正确使用$ this和self的示例:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?>

这是非静态和静态成员变量错误使用$ thisself的示例:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo self::$non_static_member . ' '
           . $this->static_member;
    }
}

new X();
?>

这是成员函数带有$ this的多态的示例:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        $this->foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

这是通过将self用于成员函数来抑制多态行为的示例:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        self::foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>
The idea is that $this->foo() calls the foo() member function of whatever >is the exact type of the current object. If the object is of type X, it thus >calls X::foo(). If the object is of type Y, it calls Y::foo(). But with >self::foo(), X::foo() is always called.

从http://www.phpbuilder.com/board/showthread.php?t=10354489:

通过http://board.phpbuilder.com/member.php?145249-laserlight

" self"(不是$ self)是指类的类型,而" $ this"是指该类的当前实例。 " self"用于静态成员函数,以允许我们访问静态成员变量。 $ this用于非静态成员函数,是对调用成员函数的类的实例的引用。

因为this是一个对象,所以我们可以像$ this-> member那样使用它。

因为self不是对象,所以它基本上是一种自动引用当前类的类型,我们可以像下面这样使用它:self :: member

$ this->用于引用类变量(成员变量)或者方法的特定实例。

Example: 
$derek = new Person();

$ derek现在是Person的特定实例。
每个人都有一个名字和一个姓氏,但是$ derek有一个特定的名字和姓氏(Derek Martin)。在$ derek实例中,我们可以将它们称为$ this-> first_name和$ this-> last_name

ClassName ::用于指代该类型的类及其静态变量,静态方法。如果有帮助,我们可以在脑海中将"静态"一词替换为"共享"。因为它们是共享的,所以它们不能引用$ this,后者引用的是特定实例(未共享)。静态变量(即静态$ db_connection)可以在一种对象的所有实例之间共享。例如,所有数据库对象共享一个连接(静态$ connection)。

静态变量示例:
假设我们有一个带有单个成员变量的数据库类:static $ num_connections;
现在,将其放入构造函数中:

function __construct()
{
    if(!isset $num_connections || $num_connections==null)
    {
        $num_connections=0;
    }
    else
    {
        $num_connections++;
    }
}

正如对象具有构造函数一样,它们也具有析构函数,这些析构函数在对象死亡或者未设置时执行:

function __destruct()
{
    $num_connections--;
}

每当我们创建一个新实例时,它将使我们的连接计数器增加一个。每次我们销毁或者停止使用实例时,连接计数器都会减少一。通过这种方式,我们可以监视正在使用的数据库对象实例的数量:

echo DB::num_connections;

由于$ num_connections是静态的(共享的),它将反映活动数据库对象的总数。我们可能已经看到了用于在数据库类的所有实例之间共享数据库连接的这项技术。这样做是因为创建数据库连接需要很长时间,因此最好仅创建一个并共享它(这称为"单例模式")。

可以使用静态方法(即公共静态View :: format_phone_number($ digits)),而无需先实例化这些对象之一(即,它们在内部未引用$ this)。

静态方法示例:

public static function prettyName($first_name, $last_name)
{
    echo ucfirst($first_name).' '.ucfirst($last_name);
}

echo Person::prettyName($derek->first_name, $derek->last_name);

如我们所见,公共静态函数prettyName对对象一无所知。它只是使用我们传入的参数,就像不属于对象的普通函数一样。那么,如果我们不把它作为对象的一部分,那又何必呢?

  • 首先,将功能添加到对象可以使事物保持井井有条,因此我们知道在哪里可以找到它们。
  • 其次,它可以防止命名冲突。在一个大项目中,我们可能有两个开发人员创建getName()函数。如果一个创建了ClassName1 :: getName(),而另一个创建了ClassName2 :: getName(),则完全没有问题。没有冲突。耶静态方法!

自己::
如果要在具有要引用的静态方法的对象之外进行编码,则必须使用对象的名称View :: format_phone_number($ phone_number);进行调用。
如果在具有要引用的静态方法的对象内进行编码,则可以使用对象的名称View :: format_phone_number($ pn),也可以使用self :: format_phone_number($ pn)快捷方式

静态变量也是如此:
示例:View :: templates_path与self :: templates_path

在DB类内部,如果我们引用其他对象的静态方法,则将使用该对象的名称:
示例:Session :: getUsersOnline();

但是,如果DB类想要引用其自己的静态变量,则只会说self:
示例:self :: connection;

希望可以帮助解决问题:)

我相信问题不在于我们是否可以通过调用ClassName :: staticMember来调用类的静态成员。问题是使用self :: classmember$ this-> classmember有什么区别。

例如,无论我们使用self ::还是$$ this->`,以下两个示例都可以正常工作

class Person{
    private $name;
    private $address;

    public function __construct($new_name,$new_address){
        $this->name = $new_name;
        $this->address = $new_address;
    }
}

class Person{
    private $name;
    private $address;
    public function __construct($new_name,$new_address){
        self::$name = $new_name;
        self::$address = $new_address;
    }
}

关键字self不仅仅指"当前类",至少不是以限制我们使用静态成员的方式。在非静态成员的上下文中," self"还提供了一种绕过当前对象的vtable的方法(请参见vtable上的wiki)。就像可以使用parent :: methodName()调用函数的父版本一样,我们也可以调用self :: methodName()来调用方法的当前类实现。

class Person {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }

    public function getTitle() {
        return $this->getName()." the person";
    }

    public function sayHello() {
        echo "Hello, I'm ".$this->getTitle()."<br/>";
    }

    public function sayGoodbye() {
        echo "Goodbye from ".self::getTitle()."<br/>";
    }
}

class Geek extends Person {
    public function __construct($name) {
        parent::__construct($name);
    }

    public function getTitle() {
        return $this->getName()." the geek";
    }
}

$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();

这将输出:

Hello, I'm Ludwig the geek

     Goodbye from Ludwig the person

sayHello()使用$ this指针,因此调用vtable来调用Geek :: getTitle()。
" sayGoodbye()"使用" self :: getTitle()",因此不使用该vtable,并调用" Person :: getTitle()"。在这两种情况下,我们都处理实例化对象的方法,并且可以访问被调用函数中的$ this指针。