【问题标题】:What is the point of having $this and self:: in PHP?在 PHP 中使用 $this 和 self:: 有什么意义?
【发布时间】:2010-07-27 15:47:16
【问题描述】:

为什么 PHP 要求您显式编写 $this?如果您必须在这里使用$this,我会理解:

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

但您必须用如下所示的冗长代码显式编写它:

$this->var3 = globalFun($this->var, $this->var2[$this->anotherVar], $this->method());

相对于:

$var3 = globaFun($var, $var2[$anotherVar], method());

那么$this的意义何在?

额外的奖励问题:

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

static function getValue() {
   return self::value;
}

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

如果我们有一个 $this,它的行为就像在 Java 中一样,那不是更好吗?

【问题讨论】:

  • 这不应该有主观标签吗?例如,我个人喜欢 $(尤其是在 Perl 中),当我看到它在其他语言中丢失时,我感到非常不安。
  • 是的,IMO 我喜欢 $ 前缀,因为它可以更直观地表示变量。在代码等中快速扫描它们。(目测和以编程方式搜索)。国际海事组织。
  • @Null 因为 PHP 在设计上不是对象。 PHP 中的 OO 是一个(补丁,错误?)
  • 接近票数是怎么回事?这根本不是主观的。这是一个严肃的技术问题。我提到了美元符号,但这个问题完全不相关。
  • 这个问题绝不是主观的,也不是争论的。这是关于 PHP 的创建者做出的特定设计选择;以及这种方法的优点是什么。

标签: php language-design


【解决方案1】:

既然重新打开了,我会按照承诺在这里发帖my answer

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) { };
    }
}

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

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

我能想到几个原因。

对象属性在运行时确定

PHP 有一个叫做“动态属性”的东西。您可以在运行时为对象分配新属性。事实上,给定同一类的两个对象,一个可以具有给定属性$a,而另一个没有。示例:

$obj1 = new stdClass();
$obj2 = new stdClass();
$obj1->a = 7;

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

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

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

后果

由于这些事实,无法在编译时确定$var 是指局部变量还是属性。因此:

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

【讨论】:

  • 感谢那个有条件地“声明”变量的例子,我现在明白了为什么 JS 会“提升”变量,而不管函数中的哪个位置使用了 var 关键字。 :)
【解决方案2】:

好的,让我们不再需要到处写$this。看看这种情况:

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

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

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

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

【讨论】:

  • $bar 是一个局部变量,在 setBar() 的范围内,因为 Foo 没有名为 $bar 的成员。
  • @NullUserException:但是现在您刚刚从 PHP 中删除了一个特性:能够动态​​地将成员添加到对象。
  • @NullUserException:因为这两个动作在语义上是不同的。当您使用$this 时,您指的是一个类的一个实例。当您使用self:: 时,您指的是类本身。显然,PHP 的开发人员认为这种差异非常重要,足以保证为每种差异提供单独的语法。
  • @musicfreak:即使不是强制性的,仍然可以显式输入$this->,因此不会删除任何功能。
  • @konforce:是的,但这会变得混乱且容易出错。此外,它对功能和self:: 并没有真正的帮助。 (如何调用与方法同名的全局函数?)
【解决方案3】:

PHP 不是 OOP。

现在可以了,但有副作用。

【讨论】:

    【解决方案4】:

    实际上,我认识使用它的人。在 Java 中,即使是不必要的,因为他们觉得它会创建更清晰的代码;)我没有一个真正明确的答案,但我想,在内部,获取 $var 总是必须转换为 $this->var。所以这并不是有人故意强迫我们做 $this->var 让事情变得更复杂,而是决定不实现 $var 快捷方式。如果这有任何帮助,我不知道;)

    【讨论】:

    • self:: 可能会有类似的论点——它不是同一件事,它不在同一个空间中,它并没有真正使代码更好地隐藏差异
    • 我已经看到了使用“this”和“m_”的代码。如果你问我就过分了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 2011-01-24
    • 2011-05-06
    • 2015-06-27
    • 2012-05-04
    • 2011-04-13
    • 2012-08-29
    相关资源
    最近更新 更多