class t {
public function tt()
{
echo 1;
}
}
t::tt();
看到了吗?非静态函数也可以在类级别调用。那么如果我在static
前面添加一个关键字有什么不同public
呢?
除此之外,如果您尝试$this
在您的方法中使用,如下所示:
class t {
protected $a = 10;
public function tt() {
echo $this->a;
echo 1;
}
}
t::tt();
静态调用非静态方法时会出现致命错误:
Fatal error: Using $this when not in object context in ...\temp.php on line 11
即你的例子有点太简单了,并没有真正对应一个真实的案例;-)
另请注意,您的示例应该给您一个严格的警告(引用):
静态调用非静态方法会生成
E_STRICT
级别警告。
它实际上确实如此(至少,使用 PHP 5.3):
Strict Standards: Non-static method t::tt() should not be called statically in ...\temp.php on line 12
1
所以:不太好;-)
尽管如此,静态调用非静态方法看起来并不像任何一种好的做法(这可能是它引发严格警告的原因),因为静态方法与非静态方法的含义不同:静态方法确实不引用任何对象,而非静态方法对调用的类的实例起作用。
再说一遍:即使 PHP 允许您做某事(也许是出于历史原因——比如与旧版本的兼容性),这并不意味着您应该这样做!
静态关键字
因为静态方法可以在没有创建对象实例的情况下调用,所以伪变量 $this 在声明为静态的方法中不可用。
使用箭头运算符 -> 无法通过对象访问静态属性。
静态调用非静态方法会生成 E_STRICT 级别的警告。
仅仅因为您可以静态调用非静态方法并不意味着您应该这样做。这是不好的形式。
通常,静态方法也称为类方法,而非静态方法也称为对象方法或实例方法。
类方法和对象方法的区别在于类方法只能访问类属性(静态属性),而对象方法用于访问对象属性(同一个类实例的属性)。
静态方法和属性用于在该特定类的所有实例上或为该特定类的所有实例共享公共数据。
例如,您可以使用静态属性来跟踪实例的数量:
class A {
private static $counter = 0;
public function __construct() {
self::counter = self::counter + 1;
}
public function __destruct() {
self::counter = self::counter - 1;
}
public static function printCounter() {
echo "There are currently ".self::counter." instances of ".__CLASS__;
}
}
$a1 = new A();
$a2 = new A();
A::printCounter();
unset($a2);
A::printCounter();
请注意,静态属性计数器是私有的,因此只能由类本身和该类的实例访问,而不能从外部访问。
尚未提及的主要区别与多态行为有关。
非静态方法在派生类中重新声明时,会覆盖基类方法,并允许基于调用它们的实例类型的多态行为。这不是静态方法的情况。
PHP 5.3 引入了后期静态绑定的概念,可用于在静态继承的上下文中引用被调用的类。
是的,关键区别在于声明的方法static
无法访问对象上下文变量$this
.
此外,不在对象上下文中调用非静态方法将触发E_STRICT
错误事件。启用后,该事件的默认行为是将消息输出到错误日志(或 STDERR),但它会允许程序继续运行。
$this
此外,任何不在对象上下文中的引用尝试都将触发E_ERROR
事件。该事件的行为是将消息输出到错误日志(或 STDERR)并以状态 255 退出程序。
例如:
<?php
error_reporting(-1);
//error_reporting(E_ALL);
class DualNature {
public static function fnStatic() {
if ( isset( $this ) ) {
// never ever gets here
$myValue = $this->_instanceValue;
} else {
// always gets here
$myValue = self::$_staticValue;
}
return $myValue;
}
public function fnInstance() {
if ( isset( $this ) ) {
// gets here on instance (->) reference only
$myValue = $this->_instanceValue;
} else {
// gets here in all other situations
$myValue = self::$_staticValue;
}
return $myValue;
}
public static function fnStaticDeath() {
return $this->_instanceValue;
}
private static $_staticValue = 'no access to $this';
private $_instanceValue = '$this is available';
}
$thing = new DualNature();
echo "==========\n";
printf("DualNature::fnStatic(): \"%s\"\n", DualNature::fnStatic() );
echo "==========\n";
printf("\$thing::fnStatic(): \"%s\"\n", $thing::fnStatic() );
echo "==========\n";
printf("\$thing->fnStatic(): \"%s\"\n", $thing->fnStatic() );
echo "==========\n";
printf("DualNature::fnInstance(): \"%s\"\n", DualNature::fnInstance() );
echo "==========\n";
printf("\$thing::fnInstance(): \"%s\"\n", $thing::fnInstance() );
echo "==========\n";
printf("\$thing->fnInstance(): \"%s\"\n", $thing->fnInstance() );
echo "==========\n";
printf("\$thing->fnStaticDeath(): \"%s\"\n", $thing->fnStaticDeath() );
echo "==========\n";
echo "I'M ALIVE!!!\n";
上面的输出是:
==========
PHP Strict Standards: Non-static method DualNature::fnInstance() should not be called statically in example.php on line 45
DualNature::fnStatic(): "no access to $this"
==========
$thing::fnStatic(): "no access to $this"
==========
$thing->fnStatic(): "no access to $this"
PHP Strict Standards: Non-static method DualNature::fnInstance() should not be called statically in example.php on line 47
==========
DualNature::fnInstance(): "no access to $this"
==========
$thing::fnInstance(): "no access to $this"
==========
$thing->fnInstance(): "$this is available"
==========
PHP Fatal error: Using $this when not in object context in example.php on line 29
将错误报告级别更改为E_ALL
将抑制默认E_STRICT
警告消息(事件仍将传播),但对的无效引用$this
仍将导致致命错误并退出程序。
除了语法和功能差异之外,还有一个重要的性能差异。
您可以参考PHP 中静态和非静态方法的或多或少的详细比较。