【问题标题】:PHP's static member and instance member seems no different. Why PHP does so(Without warning)?PHP 的静态成员和实例成员似乎没有什么不同。为什么 PHP 会这样做(没有警告)?
【发布时间】:2011-08-08 20:49:21
【问题描述】:
<?php
class A {
  public function instanceFunc() {
    echo "instance";
  }

  public static function staticFunc() {
    echo "static";
  }
}

A::instanceFunc(); // instance
$a = new A();
$a->staticFunc(); // static

这意味着 PHP 中的静态方法和实例方法完全没有区别。 Zend 甚至没有抱怨它(没有警告)。

在 Zend 引擎中。静态方法和实例方法都保存在 zend_class_entry.function_table 中。

为什么 PHP 会这样?这是错误还是功能?

【问题讨论】:

标签: php php-internals


【解决方案1】:

这是Does static method in PHP have any difference with non-static method? 的潜在副本。

如果您启用了 E_STRICT 警告,您将收到一条错误消息,否则,您可以像静态方法一样静默调用非静态方法。正如此处和另一个问题的答案中所提到的,如果没有按预期写入的 $thisself,真实世界的静态/非静态方法不会走得太远。

参考文档: http://www.php.net/manual/en/language.oop5.static.php

这里有一些东西可以玩:

http://codepad.org/Gbu9T6Zv

【讨论】:

  • 调用一个静态方法实例不会发生任何事情
  • @reeeze,我不确定您的评论的含义,但是通过实例对象调用静态方法绝对没有错,并且 everything 完全按照如果它是通过类文字调用的。
【解决方案2】:

如果您尝试运行下面的代码并查看回溯输出,您将看到 PHP 在静态上下文中调用时将 instanceFunc() 转换为静态方法。但是,在实例上下文中,它会将其视为实例调用。

如果您在混合中引入实例变量(删除注释掉的行),那么在从静态调用调用 instanceFunc() 时会遇到致命错误。

这意味着 PHP 允许从静态上下文中调用所有本质上是静态的方法(不使用实例变量),但一旦该契约被破坏,就会产生错误。因此,使用静态函数似乎只是与其他面向对象语言保持一致的好习惯。

关于 staticFunc() 两个调用都表明 PHP 将它们解释为静态调用,这是意料之中的。

class A {
  private $x = 5;
  private $y = 6;
  private $z;
  public function instanceFunc() {
    //$this->z = $this->y * $this->x;
    //echo $this->z;
    var_dump(reset(debug_backtrace()));
  }

  public static function staticFunc() {
    var_dump(reset(debug_backtrace()));
  }
}
$a = new A();
A::instanceFunc(); // static call of intended instance method
$a->instanceFunc(); // instance call of instance method
A::staticFunc();
$a->staticFunc();

示例输出(使用 cmets 运行的代码):

array(6) { ["file"]=> string(59) "test.php" ["line"]=> int(19) ["function"]=>  string(12) "instanceFunc" ["class"]=> string(1) "A" ["type"]=> string(2) "::" ["args"]=>  array(0) { } } 
array(7) { ["file"]=> string(59) "test.php" ["line"]=> int(22) ["function"]=> string(12) "instanceFunc" ["class"]=> string(1) "A" ["object"]=> object(A)#8 (3) { ["x:private"]=> int(5) ["y:private"]=> int(6) ["z:private"]=> NULL } ["type"]=> string(2) "->" ["args"]=> array(0) { } } 
array(6) { ["file"]=> string(59) "test.php" ["line"]=> int(24) ["function"]=> string(10) "staticFunc" ["class"]=> string(1) "A" ["type"]=> string(2) "::" ["args"]=> array(0) { } } 
array(6) { ["file"]=> string(59) "test.php" ["line"]=> int(26) ["function"]=> string(10) "staticFunc" ["class"]=> string(1) "A" ["type"]=> string(2) "::" ["args"]=> array(0) { } }

【讨论】:

  • 回溯中有趣的东西,+1。鉴于这样做只会引发 E_STRICT 错误,我假设这是出于某些遗留/向后兼容性的原因而维护的 - 旨在最终消除它。否则,“将此方法转换为静态”行为是无稽之谈 - 你完全正确,但它仍然是无稽之谈!
  • 我同意,这很荒谬,但 PHP 不是天生的 OO 语言,所以我想您对由于遗留原因而存在的这个“错误”的怀疑是正确的。
【解决方案3】:

我不确定为什么它不会引发警告或至少不会引发错误。但是,静态和实例存在一些主要差异。静态方法不能使用非静态的类变量。通过添加一个非静态的公共/私有变量并尝试在staticFunc 中回显它,这很容易测试,这将引发错误。

我认为主要目标是了解两者之间的差异以及如何正确使用它们。至于为什么 PHP 至少不发出通知,我不知道,也许是由于它的悠闲性质。我对有更多知识的人可以给出的回应感兴趣,这只是一些额外的信息。

我确实对它进行了完整的错误报告测试,果然它确实没有发出通知或警告。


更新

进行一些测试,似乎当您将未标记的静态函数调用为静态函数时,您仍然无法使用私有/公共变量。对于正常功能,这很可能会出错。这可能就是为什么从未抛出错误或通知的原因。但是,它最好抛出一些东西,因为以这种方式使用未标记的静态函数肯定不好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2018-12-23
    • 2019-03-11
    相关资源
    最近更新 更多