你不应该静态调用非静态方法。
一些例子
class foo{
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
}
}
测试
//instance call
(new foo)->biz(); //echos foo::biz (don't worry about the :: here, its part of __METHOD__)
//static call, statically
foo::bar() // echos foo::bar
//call non-static statically
foo::biz() //in PHP7.1
<b>Deprecated</b>: Non-static method foo::biz() should not be called statically in <b>[...][...]</b> on line <b>18</b><br />
//call static non-statically
(new foo)->bar(); // echos foo::bar
以非静态方式调用 static 背后的想法是允许在非静态方法中使用静态属性。例如:
class foo{
protected static $boo = "hello";
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
echo self::$boo;
echo static::$boo; //late static binding
}
}
所以这很好,现在另一面是在静态方法中调用非静态方法。
class foo{
protected $boo = "hello";
public static function bar(){
echo __METHOD__;
$this->boo; // this is a no no, because no instance exists and therefor $this does not work
}
public function biz(){
echo __METHOD__;
}
}
还有几点需要指出
- 当调用静态 $this 不可用时,假定您将在非静态方法中使用 $this,因此静态调用它可能会导致问题。
- 当调用非静态 $this 存在时,进行静态调用没有问题,因此非静态调用静态方法不是问题。 IE。无论上下文如何,self 和 static 都可用。
- 静态属性与类的所有实例共享
- 在父级中访问的静态属性不能被子级更改(使用 self 时)
- 子级可以更改父级中访问的静态属性(使用静态、后期静态绑定时)
现在,如果您想要确切的答案:
- 静态调用实例方法;
- 非静态调用实例方法;
- 静态调用静态方法;
- 非静态调用静态方法(四个都正确?)
我们可以使用上面的类来举例说明
class foo{
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
print_r($this);
}
}
//call non-static statically
foo::biz();
结果(PHP7+)
<br />
<b>Deprecated</b>: Non-static method foo::biz() should not be called statically in <b>[...][...]</b> on line <b>15</b><br />
foo::biz //output of __METHOD__
<br />
<b>Fatal error</b>: Uncaught Error: Using $this when not in object context in [...][...]:11
Stack trace:
#0 [...][...](15): foo::biz()
#1 {main}
thrown in <b>[...][...]</b> on line <b>11</b><br />
如您所见,我们在尝试访问 $this 时遇到致命错误
结果(PHP5 的东西)
<br />
<b>Strict Standards</b>: Non-static method foo::biz() should not be called statically in <b>[...][...]</b> on line <b>16</b><br />
foo::biz<br />
<b>Notice</b>: Undefined variable: this in <b>[...][...]</b> on line <b>11</b><br />
现在我们在 pr PHP7(某些东西)中没有遇到致命错误,乍一看这似乎没问题。就像它说的那样运行很好。然而,如果你仔细观察Undefined variable: this,这实际上比致命错误更糟糕,因为现在你的类可能会产生意想不到的结果。
如果我们称之为正常:
(new foo)->biz();
结果
foo::biz //output of __METHOD__
foo Object //output of $this
(
)
所以我想给你一个关于self 和static 的简单例子,这真的很令人困惑。
class foo{
protected static $test = 'true';
public function boo(){
echo self::$test."\n";
echo static::$test."\n";
}
}
class bar extends foo{
protected static $test = 'false';
public function biz(){
echo self::$test."\n";
echo static::$test."\n";
}
}
$B = new bar;
$B->boo();
echo "--------------\n";
$B->biz();
结果
-------------- defined in parent ----
true //call boo() self
false //call boo() static
-------------- defined in child ----
false //call biz() self
false //call biz() static
当您使用static 时,它称为后期静态绑定。这意味着静态值绑定较晚。那么这到底是什么意思呢?这意味着该值是在运行时解析的,而不是在 PHP 解析类时解析的。
-
bar 是 foo 的孩子。
- 我们实例化孩子
foo,我们所有的调用都通过foo。
- 方法
boo只存在于父级,即。它不会被子方法覆盖。
- foo 的值为 'true'
- bar 的值为 'false'
对于第一个,我们得到foo的值,因为我们使用的是self,所以它只知道自己。
对于第二个,我们得到bar 的值,因为我们使用的是静态的,它绑定较晚,并且可以使用在属性$test 的声明中设置的子值。因此,即使父母对孩子一无所知(典型),它也可以使用它的值,因为它是在运行时解决的。
对于第三个,我们得到bar 的值,因为它知道自己,并且方法是自己定义的。 foo 对此方法一无所知,即使它这样做了,它也会被子进程中的减速覆盖。
对于第四个,我们再次得到bar 的值,这是因为即使使用后期静态绑定,我们也会提取相同的数据,bar 的值因为bar 是我们实例化的类,所以在运行时time 的属性中定义的值就是值。
所以最后 2 个值是相同的,这是因为 self 和 static 无论何时调用都解析相同的信息。
这可能非常令人困惑,所以希望它是有意义的。此外,正如我所展示的,不要害怕制作一些像这样的简单类并测试你得到的值。我就是这么学的。
更新
您提到使用静态调用被认为是不好的。
我认为其中大部分来自依赖问题。这是类名称和您的代码之间的紧密耦合。使用实例时,将其分配给变量并在调用 new 时使用名称 1 次。调用静态时,您每次都使用类名。这导致的问题是如果您决定重命名该类。对于实例调用,您只需将调用 new 的名称替换为静态名称,您必须在任何地方替换它。
例如考虑这个。
$foo = new foo;
$foo->one();
$foo->two();
//say you inject this into another class
$foo->three();
并将其与此进行比较。
foo::one();
foo::two();
//say you inject this into another class
foo::three();
现在假设您更改了班级名称。对于第一个,您必须在一个地方替换它。对于第二个,您必须在使用它的地方更换它。你可以通过使用字符串变量来解决这个问题。
$class = 'foo';
$class::one();
$class::two();
//say you inject this into another class
$class::three();
但是这样你也会遇到很多麻烦,因为大多数 IDE 无法解析类并进行自动完成。
此外,如果您对其他类的输入进行类型提示
class other{
public method inject(foo $foo){}
}
这在静态类上效果不佳,因为你传入的是一个字符串(类名)。
命名空间可能是个问题。使用实例化,你只需要将 use 语句放在你实例化类的文件中。使用静态,你必须把它放在任何地方,或者在每次调用中包含它。
\mystuff\foo::bar();
$foo = '\\mystuff\\foo';
$foo::bar();
我确信还有其他原因,但对我来说这些是主要原因。