PHP:为什么我会收到关于静态属性的错误


PHP: Why am I getting errors about static properties?

http://codepad.viper-7.com/I0Zqoi

我不明白这出了什么问题,也不知道如何解决,也不明白为什么。一个对编程略知一二的人能解释一下幕后发生了什么吗,比如在解释器层面?此外,我该如何解决我的问题,为什么我需要以更正的方式编写代码?你能用人类的语言告诉我,这有什么问题,以及如何让它变得更好吗?我想我的书解释得不好,里面的代码也不起作用非常感谢。

class A 
{
  private $foo = 'bar';
  function read()
  {
      echo self::$foo;
  }
}
$a = new A();
a::read();
Strict Standards: Non-static method A::read() should not be called statically in /code/I0Zqoi on line 13
Fatal error: Access to undeclared static property: A::$foo in /code/I0Zqoi on line 8

唯一的解决方法似乎是在方法前面添加"static"。显然,非静态方法不能通过静态方式访问(例如,类A{function read(){echo"whatever"};}无法由::read()访问,因为->运算符是必需的)。此外,静态属性不能被对象代码访问,即使它们存在于函数中(例如,类a{static$variable;function read(){echo$this->variable};}a->read();无法工作,因为->运算符用于访问调用静态属性的函数。)。通过将方法和属性都更改为static,可以通过静态方式访问该方法。通过将方法和属性都更改为非静态,可以使用对象实例化来访问其中任何一个。调试器抛出错误对我来说毫无意义,因为我的书中说,可以通过对非静态方法的对象代码调用从非静态方法调用静态属性。那么,调试器坏了吗?因为我已经尝试了每一种组合,并且只有当方法和属性都是静态或非静态的时,代码才能工作。:((

严格标准部分是因为a::read()是在带有::的静态上下文中调用的。在将$a声明为A的类实例后,您应该使用->运算符对变量调用read()方法:

// Proper non-static method call
$a = new A();
$a->read();

在类定义中,$foo被声明为私有属性,但没有static关键字。然后在静态上下文中使用::运算符而不是->来引用它。访问它的正确方式是L

// Proper reference to non-static $foo
function read() {
  echo $this->foo;
}

那么static到底是什么意思呢?静态方法和属性是指由所有当前和将来的类实例共享的类方法和属性。如果A::$foo已声明为:

private static $foo;

那么对于代码中的所有类CCD_ 14,将只有一个CCD_。更改$foo将影响类A的所有实例,并且$foo甚至可以在不创建类实例(如new A();)的情况下访问

同样,可以在不创建类实例的情况下调用静态方法,因为它们不会修改非静态的类属性。

// Static method call:
A::read();

要将属性和方法声明为static,只需添加static关键字:

// Property
private static $foo;
// Method
public static function foo() {}

编辑更多示例

class A
{
  // Private property (non-static)
  private $foo;
  // Public property (static)
  public static $bar = 12345;
  // Public (non-static) function to access private $foo
  public function getFoo() { return $this->foo; }
  // Public (non-static) function to set private $foo
  public function setFoo($newfoo) { $this->foo = $newfoo; }
  // Static function 
  public static function incrementBar() { self::$bar++; }
}

现在看看它在行动:

// We haven't created any class instances yet (with the 'new' operator)
// But we can access the static properties & functions:
echo A::$bar . " ";
// prints 12345
A::incrementBar();
echo A::$bar . "'n";
// prints 12346
// Now we'll start working with class instances.
// Create 2 instances of class A
$a = new A();
$a->setFoo(8888);
$b = new A();
$b->setFoo(9999);
// It's a violation of strict standards to call getFoo() statically
// And it's meaningless to do so, because $foo only exists inside a class instance!
// Can't do this... Issues a strict warning since we're calling non-static getFoo() statically
//echo A::getFoo();

// But we can call getFoo() on the class instances:
echo $a->getFoo() . " " . $b->getFoo() . "'n";
// Prints 8888 9999
// Remember $bar was 12346...
echo $a::$bar . " " . $b::$bar . "'n";
// Prints 12346 12346
// Now modify the static property $bar again
// This affects all class instances.
A::incrementBar();
echo $a::$bar . " " . $b::$bar . "'n";
// Prints 12347 12347

我也把这整件事塞进了代码板:http://codepad.viper-7.com/tV6omK

你正在读的书一定不要注意严格的标准。如果非静态函数没有尝试访问/修改非静态属性,您可以成功地静态调用它,但它会发出严格的警告。如果非静态函数确实使用$this->property修改或访问了非静态属性,这将是一个致命错误。你不能那样做。

在PHP的error_reporting中,显示所有错误的E_ALL设置实际上并不包括严格的警告。这必须用E_ALL & E_STRICT来完成。

::用于访问静态属性。如果要访问对象属性,请使用->

$a->read();

echo $this->$foo;

尽管其他答案肯定是正确的,但以下是您具体问题的答案:

调试器抛出错误对我来说毫无意义,因为我的书中说,可以通过对非静态方法的对象代码调用从非静态方法调用静态属性。那么,调试器坏了吗?因为我已经尝试了每一种组合,并且只有当方法和属性都是静态或非静态的时,代码才能工作。:(

你的书的作者认为,没有收到错误消息被认为是干净的代码。事实并非如此。您不应该有一个既可以静态调用也可以动态调用的方法,因为这两者差别太大了。动态调用用于对象,而静态调用用于类。如果有机会,我会一直尝试动态方式,因为这会减少应用程序中的耦合。

至于为什么"调试器抛出错误"(是解释器抛出E_STRICT警告,但嘿;):这种行为在PHP中已经改变了五点左右。在PHP4中,您可以静态地调用每个方法,即使它是一个动态方法。也许,你的书在事实上落后了。