在PHP中使用$ this和self ::有什么意义?

Nul*_*ion 19 php language-design

为什么PHP要求你明确写$this?我会理解你是否必须在$this这里使用:

function foo($bar) {
   $this->bar = $bar;
}
Run Code Online (Sandbox Code Playgroud)

但是你必须在看起来像这样的详细代码中明确地编写它:

$this->var3 = globalFun($this->var, $this->var2[$this->anotherVar], $this->method());
Run Code Online (Sandbox Code Playgroud)

而不是:

$var3 = globaFun($var, $var2[$anotherVar], method());
Run Code Online (Sandbox Code Playgroud)

那有什么意义$this呢?

额外奖金问题:

为什么我们必须区分静态引用和实例?我们为什么需要:

static function getValue() {
   return self::value;
}
Run Code Online (Sandbox Code Playgroud)

如果有问题的变量/方法是静态的,PHP不能在运行时找到?现在,如果我想将方法​​从静态更改为非静态,我必须将所有这些替换self::$this->(反之亦然).

如果我们的$this行为与Java一样,那会不会更好?

Art*_*cto 15

由于重新开放,我将按照承诺在这里发布我的答案.

TL; DR版本如果不需要限定成员访问权限,则不仅会有性能损失,而且同一行代码可以同时表示字段访问和本地变量访问,具体取决于代码路径.

完整版本

在PHP中,表中始终有一个活动的符号表.这可以是全局符号表,也可以是函数/方法本地符号表(顺便说一句,它是由懒惰构建的).除了编译变量之外的超全局和优化,当$var请求变量时,它会在当前符号表中查找.由于对象属性不是存在于符号表中,而是存在于对象(实例属性)或与类关联的结构(静态属性)中,因此查找$var永远不会返回属性.

要将给定变量带入函数范围,您必须通过创建引用来明确表示您的意图.例子:

$myglobal = 7;
class A {
    private $prop;
    public function meth() {
        global $myglobal; //bring a global to the current scope
        $prop =& $this->prop; //brings a property to the current scope
        $local = 4;
        $lambda = function () use (&$local) { };
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,这只是一种更复杂的方式来表达当前发生的事情.问题是为什么会出现这种行为?

毕竟,在Java中我们只需要this.prop在有一个名为prop隐藏属性的局部变量时键入.为什么这不是PHP的好选择?

我可以想到几个原因.

对象属性在运行时确定

PHP有一种称为"动态属性"的东西.您可以在运行时为对象分配新属性.事实上,给定同一类的两个对象,一个可以具有给定属性$a而另一个不具有给定属性.例:

$obj1 = new stdClass();
$obj2 = new stdClass();
$obj1->a = 7;
Run Code Online (Sandbox Code Playgroud)

在PHP中,定义的局部变量在运行时确定

变量不必声明; 因此,根据代码路径,在某些时候可以定义变量,也可以不定义变量.为了增加对伤害的侮辱,我们还有一个名为"变量变量"的怪物.例:

class A {
    private $g = 3;
    public function func($varname) {
        if (rand(1,2) == 1) {
            $g = 4; //no block scope; the scope is the function's
        }
        $$varname = 5; //god knows what's happening here
        //if local variables hid properties, we'd have trouble
    }
}
Run Code Online (Sandbox Code Playgroud)

在Java中,给定标识符也可以在同一函数内表示局部变量和属性,但是:

  • 不在同一个块中(在PHP中,函数中的所有块共享完全相同的范围).
  • 如果您隐藏了房产,则会收到警告.
  • 至关重要的是,在任何给定的标识符出现时,它既可以是属性,也可以是局部变量,有时不能是另一个,也可能是另一个.

后果

由于这些事实,在编译时无法确定是否$var涉及局部变量或属性.所以:

  • 在运行时,每次发生变量时,都必须首先在本地符号表中查找,然后在实例属性表中查找,最后在静态属性列表中查找,或者任何其他顺序(因为不能有实例)并且需要声明具有相同名称和静态属性的静态属性,这里会有一些优化潜力,但重点是).这意味着在最坏的情况下,符号必须在三个不同的地方被查找.从性能角度来看,这很糟糕.
  • 给定的符号出现在不同的场合可能意味着不同的事物.这是灾难的秘诀.


Sas*_*gov 14

好的,让我们不再需要在$this任何地方写作.看看这种情况:

class Foo {
    public function setBar($value) {
        $bar = $value;
    }
}
$foo = new Foo();
$foo->setBar('some value');
Run Code Online (Sandbox Code Playgroud)

$bar局部变量还是成员$foo

必须有一些区别.他们可以允许使用var关键字声明局部变量,但这不会向后兼容,并且对于从旧版本的PHP升级的人来说会非常混乱.

同样的事情适用于self::.解释器如何知道您要调用的函数是全局的还是特定于该类的?

  • @NullUserException:但是现在你刚从PHP中删除了一个功能:能够动态​​地向对象添加成员. (7认同)
  • @NullUserException:因为这两个动作在语义上是不同的.当你使用`$ this`时,你指的是*类的实例*.当你使用`self ::`时,你指的是*类本身*.很显然,PHP的开发人员认为这种差异非常重要,可以保证为每个人提供单独的语法. (3认同)

Gui*_*ois 6

PHP不是OOP.

现在是,但有副作用.