在PHP5中,使用self和$this有什么区别?

什么时候合适?


当前回答

这里有一个小的基准(第7.2.24节):

            Speed (in seconds)  Percentage
$this->     0.91760206222534    100
self::      1.0047659873962     109.49909865716
static::    0.98066782951355    106.87288857386

4000 000次运行的结果。结论:没关系。这是我使用的代码:

<?php

class Foo
{
  public function calling_this() { $this->called(); }
  public function calling_self() { self::called(); }
  public function calling_static() { static::called(); }
  public static function called() {}
}

$foo = new Foo();
$n = 4000000;
$times = [];

// warmup
for ($i = 0; $i < $n; $i++) { $foo->calling_this(); }
for ($i = 0; $i < $n; $i++) { $foo->calling_self(); }
for ($i = 0; $i < $n; $i++) { $foo->calling_static(); }

$start = microtime(true);
for ($i = 0; $i < $n; $i++) { $foo->calling_this(); }
$times["this"] = microtime(true)-$start;

$start = microtime(true);
for ($i = 0; $i < $n; $i++) { $foo->calling_self(); }
$times["self"] = microtime(true)-$start;

$start = microtime(true);
for ($i = 0; $i < $n; $i++) { $foo->calling_static(); }
$times["static"] = microtime(true)-$start;

$min = min($times);
echo $times["this"] . "\t" . ($times["this"] / $min)*100 . "\n";
echo $times["self"] . "\t" . ($times["self"] / $min)*100 . "\n";
echo $times["static"] . "\t" . ($times["static"] / $min)*100 . "\n";

其他回答

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

Example: 
$derek = new Person();

$derek现在是Person的一个特定实例。每个人都有一个first_name和一个last_name,但$derek有一个特定的first_name和last_name(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是静态的(共享的),所以它将反映活动数据库对象的总数。您可能已经看到这种技术用于在数据库类的所有实例之间共享数据库连接。这样做是因为创建数据库连接需要很长时间,所以最好只创建一个并共享它(这称为Singleton模式)。

静态方法(即,public Static 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_prhone_number

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

在DB类中,如果我们引用其他对象的静态方法,我们将使用对象的名称:示例:会话::getUsersOnline();

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

简短回答

使用$this表示当前对象使用self指代当前类别。换句话说,使用$this->非静态成员的成员,对静态成员使用self::$member。

完整答案

以下是非静态和静态成员变量$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();
?>

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

<?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();
?>

其思想是$this->foo()调用当前对象的任何类型的foo(()成员函数。如果对象是X类型,那么它将调用X::foo()。如果对象类型为Y,则调用Y::foo()。但是对于self::foo(),总是调用X::foo()。

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

通过http://board.phpbuilder.com/member.php?145249-激光灯

关键字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();

这将输出:

你好,我是极客路德维希路德维希再见了

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

根据静态关键字,没有任何$self。只有$this用于引用类(对象)的当前实例,self用于引用类的静态成员。对象实例和类之间的区别在这里发挥作用。

在PHP中,使用self关键字访问静态财产和方法。

问题是,无论method()是否声明为静态,都可以在任何地方用self::method(。那么你应该使用哪一种?

考虑以下代码:

class ParentClass {
    function test() {
        self::who();    // will output 'parent'
        $this->who();   // will output 'child'
    }

    function who() {
        echo 'parent';
    }
}

class ChildClass extends ParentClass {
    function who() {
        echo 'child';
    }
}

$obj = new ChildClass();
$obj->test();

在本例中,self::who()将始终输出“parent”,而$this->who(()将取决于对象的类。

现在我们可以看到self是指调用它的类,而$this是指当前对象的类。

因此,只有当$this不可用时,或者当您不想让后代类覆盖当前方法时,才应该使用self。