为什么我不能使用静态方法(class :: method)的非静态方法?这是某种配置问题吗?
class Teste {
public function fun1() {
echo 'fun1';
}
public static function fun2() {
echo "static fun2" ;
}
}
Teste::fun1(); // why?
Teste::fun2(); //ok - is a static method
答案 0 :(得分:30)
PHP在静态与非静态方法上非常松散。我在这里没有注意到的一件事是,如果你在ns
的非静态方法中静态地调用非静态方法C
,$this
在{{1}内将引用您的ns
。
C
如果你有严格的错误报告,这实际上是某种错误,但不是。
答案 1 :(得分:24)
这是PHP的一个着名的“怪癖”。设计是为了防止反向传播,以便在不久前我们实际实例化一个对象(记住,PHP是解释的,不是编译的)。但是,如果未实例化对象,则访问任何非静态成员via scope resolution运算符将发出致命错误。
由PHP.net提供:
class User {
const GIVEN = 1; // class constants can't be labeled static nor assigned visibility
public $a=2;
public static $b=3;
public function me(){
echo "print me";
}
public static function you() {
echo "print you";
}
}
class myUser extends User {
}
// Are properties and methods instantiated to an object of a class, & are they accessible?
//$object1= new User(); // uncomment this line with each of the following lines individually
//echo $object1->GIVEN . "</br>"; // yields nothing
//echo $object1->GIVE . "</br>"; // deliberately misnamed, still yields nothing
//echo $object1->User::GIVEN . "</br>"; // yields nothing
//echo $object1->a . "</br>"; // yields 2
//echo $object1->b . "</br>"; // yields nothing
//echo $object1->me() . "</br>"; // yields print me
//echo $object1->you() . "</br>"; // yields print you
// Are properties and methods instantiated to an object of a child class, & are accessible?
//$object2= new myUser(); // uncomment this line with each of the following lines individually
//echo $object2->GIVEN . "</br>"; // yields nothing
//echo $object2->a . "</br>"; // yields 2
//echo $object2->b . "</br>"; // yields nothing
//echo $object2->me() . "</br>"; // yields print me
//echo $object2->you() . "</br>"; // yields print you
// Are the properties and methods accessible directly in the class?
//echo User::GIVEN . "</br>"; // yields 1
//echo User::$a . "</br>"; // yields fatal error since it is not static
//echo User::$b . "</br>"; // yields 3
//echo User::me() . "</br>"; // yields print me
//echo User::you() . "</br>"; // yields print you
// Are the properties and methods copied to the child class and are they accessible?
//echo myUser::GIVEN . "</br>"; // yields 1
//echo myUser::$a . "</br>"; // yields fatal error since it is not static
//echo myUser::$b . "</br>"; // yields 3
//echo myUser::me() . "</br>"; // yields print me
//echo myUser::you() . "</br>"; // yields print you
?>
答案 2 :(得分:14)
这是PHP 4向后兼容性。在PHP 4中,对象方法和作为静态类方法编写的全局函数之间没有区别。因此两者都有效。
然而,随着PHP 5对象模型的变化 - http://php.net/oop5 - 引入了静态关键字。
然后从PHP 5.1.3开始,您会得到关于以下内容的严格标准警告:
严格标准:不应静态调用非静态方法Foo :: bar()
和/或:
严格标准:非静态方法Foo :: bar()不应该静态调用,假设来自不兼容的上下文的$ this
您应该已为您的开发设置启用了它。所以它只是向后兼容到语言不能足够差异的时间,所以这是在运行时“定义”的。
现在您可以在代码中定义它,但是如果您仍然将其称为“错误”,则代码不会中断。
一些Demo触发错误消息并显示不同PHP版本的更改行为:http://3v4l.org/8WRQH
答案 3 :(得分:13)
PHP 4没有静态关键字(在函数声明上下文中),但仍然允许使用::
静态调用方法。为了向后兼容的目的,这在PHP 5中继续。
答案 4 :(得分:6)
您可以执行此操作,但如果您在名为$this
fun1()
,则代码会出错
答案 5 :(得分:6)
警告 在PHP 7中,不推荐静态调用非静态方法,并将生成E_DEPRECATED警告。将来可能会删除对静态调用非静态方法的支持。
答案 6 :(得分:1)
在大多数语言中,您需要拥有该类的实例才能执行实例方法。当您使用范围解析运算符调用实例方法时,PHP似乎会创建一个临时实例。
答案 7 :(得分:1)
不确定为什么PHP允许这样做,但你不想养成这样做的习惯。您的示例只能起作用,因为它不会尝试访问该类的非静态属性。
简单的事情:
<?php
class Foo {
private $color;
public function bar() {
echo 'before';
$this->color = "blue";
echo 'after';
}
}
Foo::bar();
会导致致命错误
答案 8 :(得分:0)
我注意到如果从类中调用非静态方法self :: test(),则不会发出严格标准的警告,就像调用Class :: test()时一样。我相信这与LSB无关,因为我的课程没有扩展(在PHP 5.5上测试过)?
答案 9 :(得分:0)
静态和非静态调用相同方法的一种方法是使用魔术方法 __call
和 __callStatic
。
FluentMath 类(下面的代码)是一个示例,您可以在其中静态调用方法 add
或 subtract
:
$res1 = FluentMath::add(5) // add method called statically
->add(3) // add method called non-statically
->subtract(2)
->result();
$res2 = FluentMath::subtract(1)->add(10)->result();
class FluentMath
{
private $result = 0;
public function __call($method, $args)
{
return $this->call($method, $args);
}
public static function __callStatic($method, $args)
{
return (new static())->call($method, $args);
}
private function call($method, $args)
{
if (! method_exists($this , '_' . $method)) {
throw new Exception('Call undefined method ' . $method);
}
return $this->{'_' . $method}(...$args);
}
private function _add($num)
{
$this->result += $num;
return $this;
}
private function _subtract($num)
{
$this->result -= $num;
return $this;
}
public function result()
{
return $this->result;
}
}
如果您想了解该类的工作原理,请查看: