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

什么时候合适?


当前回答

简短回答

使用$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-激光灯

其他回答

我认为问题不在于是否可以通过调用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;
    }
}

$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;

self::用于当前类的关键字,基本上用于访问静态成员、方法和常量。但是在$this的情况下,不能调用静态成员、方法和函数。

您可以在另一个类中使用self::关键字并访问静态成员、方法和常量。当它将从父类扩展时,在$this关键字的情况下也是如此。当另一个类将从父类扩展时,您可以访问该类中的非静态成员、方法和函数。

下面给出的代码是self::和$this关键字的示例。只需复制并粘贴代码文件中的代码,即可看到输出。

class cars{
    var $doors = 4;
    static $car_wheel = 4;

    public function car_features(){
        echo $this->doors . " Doors <br>";
        echo self::$car_wheel . " Wheels <br>";
    }
}

class spec extends cars{
    function car_spec(){
        print(self::$car_wheel . " Doors <br>");
        print($this->doors . " Wheels <br>");
    }
}

/********Parent class output*********/

$car = new cars;
print_r($car->car_features());

echo "------------------------<br>";

/********Extend class from another class output**********/


$car_spec_show = new spec;

print($car_spec_show->car_spec());

在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。

这里有一个小的基准(第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";