何时在$ this上使用self?


Answers:


1727

简短答案

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

完整答案

这里是一个例子正确的使用$thisself用于非静态和静态成员变量:

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

这是带有for成员函数的多态示例$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();
?>

这是通过使用for成员函数来抑制多态行为的示例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()当前对象的确切类型的成员函数。如果对象是type X,则调用X::foo()。如果对象是type Y,则调用Y::foo()。但是X::foo()总是使用self :: foo()来调用。

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

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


330
这个答案过于简单。如其他答案中所指出的,self与范围解析运算符::一起使用以引用当前类;这可以在静态和非静态上下文中完成。此外,使用$this静态方法(而不是引用字段)是完全合法的。
Artefacto

50
如果您在5.3+上,也可以考虑使用static ::而不是:: self。否则,这可能会引起您难以置信的头痛,请参阅下面的答案以了解原因。
Sqoo 2011年

25
-1。该答案具有误导性,请阅读其他答案以获取更多信息。
Pacerier

6
它可能被过度简化,但是它回答了我的基本水平问题,而没有引起我的头爆。我确实获得了更多有用的信息,但是到目前为止,我只是想弄清楚为什么我用$ this-> attrib和class常量使用self :: constant来访问类属性。这有助于我更好地理解
MydKnight 2015年

$this::
詹姆斯

742

关键字自不只是指“当前类的,至少不会在某种程度上,限制你的静态成员。在非静态成员的上下文中,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被调用函数中的指针。


3
如果您从一般规则开始而不是例外,那么答案会更好。这是风格问题,而不是技术专长。这是我所见过的关于self ::和$ this->的区别的最好的例子,但是通过首先反驳一个概念来隐藏它是可耻的。
adjwilli 2014年

3
@adjwilli:那为什么风格不好?如果OP的期望(命题)首先被拒绝(对立),然后以综合的形式给出解释,这是否会提高意识?
hakre 2014年

1
我发现“当前课程”确实有问题。由于该单词组合既可以理解为“所在类”,也可以理解为“ self对象的类”(实际上是static)。
Jakumi

$this::
詹姆斯

1
@James-没有充分的理由使用$this::;所有可能的情况都已被更常用的语法覆盖。根据你的意思,使用$this->self::static::
ToolmakerSteve

461

不要使用self::,使用static::

自我的另一方面::值得一提。恼人的self::是指定义时的范围而不是执行时的范围。考虑使用两种方法的简单类:

class Person
{

    public static function status()
    {
        self::getStatus();
    }

    protected static function getStatus()
    {
        echo "Person is alive";
    }

}

如果我们打电话,Person::status()我们将看到“人还活着”。现在考虑当我们创建一个继承自此的类时会发生什么:

class Deceased extends Person
{

    protected static function getStatus()
    {
        echo "Person is deceased";
    }

}

进行调用时,Deceased::status()我们希望看到“ Person已死”,但是我们看到的是“ Person仍然存在”,因为在定义调用时,作用域包含原始方法定义self::getStatus()

PHP 5.3有一个解决方案。该static::解决运营商实施“后期静态绑定”,这是说,它必然要调用的类范围的一个奇特的方式。将行更改status()static::getStatus(),结果就是您所期望的。在较旧版本的PHP中,您将必须找到解决方法。

参见PHP文档

所以回答问题不是按要求...

$this->引用当前对象(类的实例),而static::引用类


6
类常量呢?
凯文·邦德

53
“我们称呼死者:: status()为已死者”。否。这是一个静态函数调用,因此不涉及多态性。
cquezel

2
在PHP的所有缺陷中,我从来都不认为这是疯狂的。它们还如何允许编码人员在当前类上指定方法(而不是在vtable中查找方法)?如果他们以不同的方式命名(也许带有下划线),那么想要此功能的人就会批评它丑陋。否则,无论他们使用什么理智的名字,似乎总是很容易感到困惑,人们会批评它是“疯狂”的行为,可能会忘记方法的调度方式。
TNE

2
该示例对我来说似乎令人困惑:我将getStatus方法视为类实例而不是类的实例。
贾尼斯·埃默里斯(JānisElmeris)

1
@Sqoo-说“请勿使用self ::,请使用static ::”是很奇怪的一点-这些是故意不相同的操作。我认为您真正要说的是“如果使用实际的类名'MyClass ::'而不是'self ::'会更清楚。也就是说,如果您想要的行为self::,则可以减少容易混淆的,通过使用特定的类名,如MyClass::
ToolmakerSteve

248

为了真正理解在谈论selfvs 时我们在谈论什么$this,我们需要从概念和实践层面上进行实际挖掘。我真的没有任何答案可以适当地做到这一点,所以这是我的尝试。

让我们开始讨论什么是对象

概念上的类和对象

那么,什么?许多人将其定义为对象的蓝图模板。实际上,您可以在此处阅读有关PHP中的类的更多信息。在某种程度上,这就是真正的含义。让我们看一课:

class Person {
    public $name = 'my name';
    public function sayHello() {
        echo "Hello";
    }
}

如您所知,该类上有一个名为的属性,$name以及一个名为的方法(函数)sayHello()

这是非常值得注意的是,重要的是静态结构。这意味着Person,一旦定义了该类,则在您看到的所有地方总是相同的。

另一方面,对象就是所谓的类的实例。这意味着我们采用了该类的“蓝图”,并使用它来创建动态副本。现在,此副本已专门与其存储在其中的变量相关联。因此,对实例的任何更改都是该实例的本地更改。

$bob = new Person;
$adam = new Person;
$bob->name = 'Bob';
echo $adam->name; // "my name"

我们使用运算符创建类的新实例new

因此,我们说一个类是一个全局结构,一个对象是一个局部结构。不用担心这种有趣的->语法,我们将对此进行一些介绍。

我们应该讨论的另一件事是,我们可以检查实例是否instanceof是特定的类:$bob instanceof Person如果该$bob实例是使用Person该类的子类创建的,则返回布尔值Person

定义状态

因此,让我们深入探讨一个类实际包含的内容。一个类包含5种类型的“事物”:

  1. 属性 -将它们视为每个实例将包含的变量。

    class Foo {
        public $bar = 1;
    }
  2. 静态属性 -将它们视为在类级别共享的变量。意味着它们永远不会被每个实例复制。

    class Foo {
        public static $bar = 1;
    }
  3. 方法 -这些是每个实例将包含的功能(并对实例进行操作)。

    class Foo {
        public function bar() {}
    }
  4. 静态方法 -这些是在整个类中共享的函数。它们不对实例进行操作,而是仅对静态属性进行操作。

    class Foo {
        public static function bar() {}
    }
  5. 常量 -类解析的常量。这里不做更深入的介绍,但是为了完整性起见:

    class Foo {
        const BAR = 1;
    }

因此,基本上,我们使用有关静态的 “提示”将信息存储在类和对象容器上,这些“提示” 标识信息是否共享(因此是静态)(是否是共享)(因此是动态)。

状态与方法

在方法内部,对象实例由$this变量表示。该对象的当前状态在那里,并且更改(更改)任何属性都将导致该实例(但其他实例)不发生更改。

如果静态调用方法,则不会定义$this变量。这是因为没有实例与静态调用关联。

这里有趣的是如何进行静态调用。因此,让我们谈谈如何访问状态:

进入国

因此,既然我们已经存储了该状态,就需要访问它。这能有点棘手(或方式多一点),所以让我们拆到这两种观点:从一个实例/类以外的(说从一个普通的函数调用,或从全球范围),以及一个实例内部/ class(从对象的方法内部)。

从实例/类的外部

从实例/类的外部,我们的规则非常简单且可预测。我们有两个运算符,每个运算符都会立即告诉我们是否要处理实例或静态类:

  • ->- 对象的操作 -当我们访问一个实例这是始终使用。

    $bob = new Person;
    echo $bob->name;

    重要的是要注意,调用Person->foo没有任何意义(因为它Person是一个类,而不是实例)。因此,这是一个解析错误。

  • ::- 范围分辨率的操作员 -这总是被用来访问一类的静态属性或方法。

    echo Foo::bar()

    另外,我们可以用相同的方式在对象上调用静态方法:

    echo $foo::bar()

    这是非常需要注意的是,我们这样做时,重要的来自外部的对象的实例从隐藏的bar()方法。这意味着它与运行完全相同:

    $class = get_class($foo);
    $class::bar();

因此,$this在静态调用中未定义。

从实例/类内部

这里的情况有所变化。使用相同的运算符,但是它们的含义变得明显模糊。

对象的操作 ->仍然是用来对对象的实例状态的呼叫。

class Foo {
    public $a = 1;
    public function bar() {
        return $this->a;
    }
}

使用object-operator:在的实例()bar()上调用方法,将产生的实例版本。$fooFoo$foo->bar()$a

这就是我们的期望。

::尽管运算符的含义有所变化。这取决于对当前函数的调用上下文:

  • 在静态环境中

    在静态上下文中,使用进行的任何调用::也将是静态的。让我们看一个例子:

    class Foo {
        public function bar() {
            return Foo::baz();
        }
        public function baz() {
            return isset($this);
        }
    }

    调用Foo::bar()baz()静态调用该方法,因此$this不会填充该方法。值得注意的是,在最新版本的PHP(5.3+)中,这将触发E_STRICT错误,因为我们正在静态地调用非静态方法。

  • 在实例上下文中

    另一方面,在实例上下文中,使用::进行的调用取决于调用的接收者(我们正在调用的方法)。如果将方法定义为static,则它将使用静态调用。如果不是,它将转发实例信息。

    因此,查看上面的代码,由于“静态”调用发生在实例上下文内部,因此调用$foo->bar()将返回true

合理?不这么认为。令人困惑。

快捷关键字

由于使用类名将所有内容捆绑在一起非常麻烦,因此PHP提供了3个基本的“捷径”关键字来简化范围解析。

  • self-这是指当前的类名。因此与类中self::baz()的内容相同(类上的任何方法)。Foo::baz()Foo

  • parent -这是指当前类的父级。

  • static-这是指被调用的类。由于继承,子类可以覆盖方法和静态属性。因此,使用static而不是类名来调用它们可以使我们确定调用的来源而不是当前级别。

例子

理解这一点的最简单方法是开始看一些示例。让我们选择一个类:

class Person {
    public static $number = 0;
    public $id = 0;
    public function __construct() {
        self::$number++;
        $this->id = self::$number;
    }
    public $name = "";
    public function getName() {
        return $this->name;
    }
    public function getId() {
        return $this->id;
    }
}

class Child extends Person {
    public $age = 0;
    public function __construct($age) {
        $this->age = $age;
        parent::__construct();
    }
    public function getName() {
        return 'child: ' . parent::getName();
    }
}

现在,我们还在这里研究继承。暂时忽略这是一个不好的对象模型,但是让我们看一下使用此对象会发生什么:

$bob = new Person;
$bob->name = "Bob";
$adam = new Person;
$adam->name = "Adam";
$billy = new Child;
$billy->name = "Billy";
var_dump($bob->getId()); // 1
var_dump($adam->getId()); // 2
var_dump($billy->getId()); // 3

因此,ID计数器在实例和子实例之间共享(因为我们正在使用self它来访问它。如果使用static,则可以在子类中覆盖它)。

var_dump($bob->getName()); // Bob
var_dump($adam->getName()); // Adam
var_dump($billy->getName()); // child: Billy

请注意,我们每次都在执行Person::getName() 实例方法。但是我们parent::getName()在一种情况(子案例)中使用来做到这一点。这就是使此方法功能强大的原因。

警告语#1

注意,调用上下文是确定是否使用实例的因素。因此:

class Foo {
    public function isFoo() {
        return $this instanceof Foo;
    }
}

并非总是如此。

class Bar {
    public function doSomething() {
        return Foo::isFoo();
    }
}
$b = new Bar;
var_dump($b->doSomething()); // bool(false)

现在,这里真的很奇怪。我们正在调用其他类,但是$this传递给该Foo::isFoo()方法的是的实例$bar

这可能会导致各种错误和概念上的WTF-ery。所以我强烈建议避免了::运营商从实例方法中的任何东西,除了这三个虚拟的“捷径”关键字(staticself,和parent)。

警示语#2

请注意,静态方法和属性由所有人共享。这使得它们基本上是全局变量。与全局变量一起带来的所有相同问题。因此,除非您对真正的全局性感到满意,否则我真的很犹豫将信息存储在静态方法/属性中。

警告语#3

通常,您需要使用static而不是使用所谓的Latex-Static-Binding self。但是请注意,它们不是一回事,所以说“始终使用static而不是代替self确实是近视的。相反,停下来想一想您要进行的调用,并考虑是否希望子类能够覆盖该静态解析呼叫。

TL / DR

太糟糕了,请回头阅读。可能太长了,但是太长了,因为这是一个复杂的主题

TL / DR#2

好的。简而言之,self用于引用一个类中的当前类名称,其中as $this表示当前对象实例。请注意,这self是复制/粘贴的快捷方式。您可以使用您的班级名称安全地替换它,它将正常运行。但是它$this是一个动态变量,无法提前确定(甚至可能不是您的课程)。

TL / DR#3

如果使用对象运算符(->),则您始终知道您正在处理实例。如果使用scope-resolution-operator(::),则需要有关上下文的更多信息(我们是否已经在对象上下文中?我们是否在对象外部?等等)。



好吧…… $this如果您遵循“严格标准”并且不以静态方式调用未定义为静态的方法,则不会定义。我看到您在这里解释的结果:3v4l.org/WeHVM同意,真的很奇怪。
MarkAchée2013年

2
完全阅读了详细说明后,我懒于再次滚动到上方以对其进行投票。只是开玩笑,我确实赞成:D。谢谢,这是非常有用的。
2013年

3
添加一个关于self :: $ property和self :: property之间的区别的清晰解释会很好。我认为那也很令人困惑
Tommaso Barbugli 2014年

1
自PHP 7以来,WoC#1的行为有所不同。不会被Foo::isFoo()静态调用$this。我认为这是更直观的行为。- 如果从扩展,则给出另一个不同的结果。然后,该调用实际上将在实例上下文内(不特定于PHP7)。BarFooFoo::isFoo()
2016年

117

self(不是$ self)是指类的类型,其中as $this是指类的当前实例self用于静态成员函数,以允许您访问静态成员变量。$this在非静态成员函数中使用,是对调用成员函数的类的实例的引用。

因为this是一个对象,所以您可以像这样使用它:$this->member

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


97

$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对对象一无所知。它只是与您传入的参数一起使用,就像不属于对象的普通函数一样。那么,如果我们不把它作为对象的一部分,那又何必呢?

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

SELF :: 如果您在具有要引用的静态方法的对象之外进行编码,则必须使用对象的名称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;

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


好答案。我只想指出,在引用静态属性时,需要使用$符号。例如self::$templates_path
henrywright

30

这篇博客文章

  • self 指当前班级
  • self 可用于调用静态函数并引用静态成员变量
  • self 可以在静态函数中使用
  • self 也可以通过绕过vtable来关闭多态行为
  • $this 指当前对象
  • $this 可用于调用静态函数
  • $this不应用于调用静态成员变量。使用self代替。
  • $this 不能在静态函数中使用

26

在PHP中,您可以使用self关键字来访问静态属性和方法。

问题在于,无论是否声明为静态,都可以$this->method()self::method()任何地方替换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指的是调用它的类,而self指的是当前对象$this

因此,仅在$this不可用或不想让子孙类覆盖当前方法时,才应使用self 。


22

在类定义内部,$this引用当前对象,同时self引用当前类。

必须使用引用类元素self,并使用引用对象元素$this

self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable  

21

这是对非静态和静态成员变量正确使用$ 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();
?> 


16

我相信问题不在于您是否可以通过调用来调用类的静态成员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;
    }
}

尤其有趣的是,您以“我认为问题不是您是否可以通过调用ClassName :: staticMember来调用类的静态成员开始。问题是使用self :: classmember和$ this-> classmember有什么区别”然后您将继续显示任何差异。实际上,您显示了两个选项工作相同的实例。-1
Buttle Butkus

不过有用。范围是关于分辨率的,这部分在php手册中尚不清楚。我仍然发现它很有用
雷诺阿

2
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
K-Gun

16

self 引用当前类(在其中被称为),

$this引用当前对象。您可以使用静态而不是自我。参见示例:

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

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

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

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

输出:亲子


16
  • 指向的对象指针指向$this当前对象。
  • 类值static引用当前对象。
  • 类值self是指其定义所在的确切类。
  • 类值parent引用其定义所在的确切类的父级。

请参见以下示例,其中显示了重载。

<?php

class A {

    public static function newStaticClass()
    {
        return new static;
    }

    public static function newSelfClass()
    {
        return new self;
    }

    public function newThisClass()
    {
        return new $this;
    }
}

class B extends A
{
    public function newParentClass()
    {
        return new parent;
    }
}


$b = new B;

var_dump($b::newStaticClass()); // B
var_dump($b::newSelfClass()); // A because self belongs to "A"
var_dump($b->newThisClass()); // B
var_dump($b->newParentClass()); // A


class C extends B
{
    public static function newSelfClass()
    {
        return new self;
    }
}


$c = new C;

var_dump($c::newStaticClass()); // C
var_dump($c::newSelfClass()); // C because self now points to "C" class
var_dump($c->newThisClass()); // C
var_dump($b->newParentClass()); // A because parent was defined *way back* in class "B"

大多数时候,您想引用当前类,这就是为什么要使用staticor的原因$this。但是,有时需要这样做 self是因为无论原始类有什么扩展,都想要原始类。(非常,很少)


14

正如这里没有人谈论性能一样,这是我做的一个小型基准测试(5.6):

 Name     | Time    | Percent  
----------|---------|---------  
 $this->  | 0.99163 | 106.23%  
 self::   | 0.96912 | 103.82%  
 static:: | 0.93348 | 100%

这些是2000000次运行的结果,这是我使用的代码:

<?php

require '../vendor/autoload.php';

// My small class to do benchmarks
// All it does is looping over every test x times and record the
//   time it takes using `microtime(true)`
// Then, the percentage is calculated, with 100% being the quickest
// Times are being rouned for outputting only, not to calculate the percentages
$b = new Tleb\Benchmark\Benchmark(2000000);

class Foo
{
    public function calling_this()
    {
        $this->called();
    }

    public function calling_self()
    {
        self::called();
    }

    public function calling_static()
    {
        static::called();
    }

    public static function called()
    {
    }
}

$b->add('$this->',  function () { $foo = new Foo; $foo->calling_this(); });
$b->add('self::',   function () { $foo = new Foo; $foo->calling_self(); });
$b->add('static::', function () { $foo = new Foo; $foo->calling_static(); });

$b->run();

1
调用无操作功能2000万次持续1秒。一定喜欢PHP。
rr- 2015年

好的旧PHP。:)但是通话= 0.001ms。这样不好吗
tleb 2015年

我认为这(以及类似的原因)就是为什么除非您缓存东西,否则ORM之类的东西会感觉很慢,而静态站点生成器才是原因。
rr- 2015年

2
从理论上讲,它应该花费1个处理器时钟周期,这大约1 / 2e9 s = 0.5 ns
Buddy

只是重新阅读我的答案。注意:它也会创建类。我不知道为什么不使用use关键字tbh,但是我没有PHP可以重做基准测试,而且我真的不希望重新安装它。
tleb

13

self::运算符一起使用时,它引用当前类,可以在静态和非静态上下文中完成。$this指对象本身。另外,使用$this静态方法(而不是引用字段)是完全合法的。


8

我遇到了同样的问题,简单的答案是:

  • $this 需要一个类的实例
  • self::

每当您使用静态方法静态属性并且要在不实例化类的对象的情况下self:调用它们时,$this都需要使用它们来调用它们,因为始终需要创建on对象。


7

$this指当前类的对象,self指当前类(非对象)。该类是对象的蓝图。因此,您定义了一个类,但是构造了对象。

因此,换句话说,使用self for staticthis for none-static members or methods

在孩子/父母的情况下,self / parent也主要用于标识孩子和父母班级的成员和方法。


7

另外因为 $this::尚未进行讨论。

仅出于提供信息的目的,从PHP 5.3开始,在处理实例化对象以获取当前作用域值时,与使用相比static::,可以$this::像这样使用。

http://ideone.com/7etRHy

class Foo
{
    const NAME = 'Foo';

    //Always Foo::NAME (Foo) due to self
    protected static $staticName = self::NAME;

    public function __construct()
    {
        echo $this::NAME;
    }

    public function getStaticName()
    {
       echo $this::$staticName;
    }
}

class Bar extends Foo
{
    const NAME = 'FooBar';

    /**
     * override getStaticName to output Bar::NAME
     */
    public function getStaticName()
    {
        $this::$staticName = $this::NAME;
        parent::getStaticName();
    }
}

$foo = new Foo; //outputs Foo
$bar = new Bar; //outputs FooBar
$foo->getStaticName(); //outputs Foo
$bar->getStaticName(); //outputs FooBar
$foo->getStaticName(); //outputs FooBar

使用上面的代码不是普遍或推荐的做法,而只是为了说明其用法,并且更多地充当“您知道吗?”的角色。参考原始海报的问题。

它也代表了的用法,$object::CONSTANT例如echo $foo::NAME;$this::NAME;


5

使用self,如果你想调用一个类的方法,而无需创建该类的对象/实例,从而节省RAM(有时使用自用于这一目的)。换句话说,它实际上是在静态地调用方法。使用this为对象的观点。


2

情况1:self可以用于类常量

 class classA { 
     const FIXED_NUMBER = 4; 
     自我:: POUNDS_TO_KILOGRAMS
}

如果要在类之外调用它,请使用classA::POUNDS_TO_KILOGRAMS来访问常量

情况2:对于静态属性

class C
     公共功能__construct(){ 
     自我:: $ _ counter ++; $ this-> num = self :: $ _ counter;
   }
}

1

据php.net有在这种情况下三个特殊的关键字:selfparentstatic。它们用于从类定义内部访问属性或方法。

$this另一方面,用于访问任何类的实例和方法,只要该类是可访问的。


-1

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());
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.