5 php oop methods static non-static
PHP中有实例方法和静态方法(就这两种类型)?那么我们可以静态或非静态地调用其中任何一个(名称是“动态”吗?)?
所以我们可以:
这四个的代码看起来怎么样?有没有什么好的网站可以解释这个?我目前正在阅读以下网址:
http://php.net/manual/en/language.oop5.basic.php
...我不明白这一点:
“$this 是对调用对象的引用(通常是该方法所属的对象,但也可能是另一个对象,如果该方法是从辅助对象的上下文中静态调用的)。”
代码如何从辅助对象静态调用方法?我的意思是,静态所有调用与非静态调用,这是什么?
您不应该静态调用非静态方法。
一些例子
class foo{
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
}
}
Run Code Online (Sandbox Code Playgroud)
测试
//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
Run Code Online (Sandbox Code Playgroud)
非静态调用 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
}
}
Run Code Online (Sandbox Code Playgroud)
所以这很好,现在的另一面是在静态方法内部调用非静态方法。
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__;
}
}
Run Code Online (Sandbox Code Playgroud)
其他一些需要指出的事情
现在,如果您想要确切的答案:
我们可以使用上面的类通过示例来展示这一点
class foo{
public static function bar(){
echo __METHOD__;
}
public function biz(){
echo __METHOD__;
print_r($this);
}
}
//call non-static statically
foo::biz();
Run Code Online (Sandbox Code Playgroud)
结果 (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 />
Run Code Online (Sandbox Code Playgroud)
如您所见,我们在尝试访问时遇到致命错误$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 />
Run Code Online (Sandbox Code Playgroud)
现在我们在 PHP7 中没有遇到致命错误(某事),乍一看这似乎没问题。就像它说的那样,这样跑就好了。然而,如果你仔细观察,Undefined variable: this这实际上比致命错误更糟糕,因为现在你的类可能会产生意想不到的结果。
如果我们称这为正常:
(new foo)->biz();
Run Code Online (Sandbox Code Playgroud)
结果
foo::biz //output of __METHOD__
foo Object //output of $this
(
)
Run Code Online (Sandbox Code Playgroud)
所以我想给你一个关于selfvs的简单例子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();
Run Code Online (Sandbox Code Playgroud)
结果
-------------- defined in parent ----
true //call boo() self
false //call boo() static
-------------- defined in child ----
false //call biz() self
false //call biz() static
Run Code Online (Sandbox Code Playgroud)
当您使用static它时,称为后期静态绑定。这意味着静态值被延迟绑定。那么这到底是什么意思呢?这意味着该值是在运行时解析的,而不是在 PHP 解析类时解析的。
bar是 的孩子foo。 foo,我们所有的调用都会通过foo。 boo仅存在于父级中,即。它不会被子方法覆盖。对于第一个,我们得到 的值,foo因为我们使用的是 self,所以它只知道它自己。
对于第二个,我们得到 的值,bar因为我们使用的是 static,它是后期绑定的,并且可以使用在属性声明中设置的子项的值$test。因此,即使父级对子级一无所知(典型),它也可以使用它的值,因为它是在运行时解析的。
对于第三个,我们得到 的值,bar因为它了解自身,并且该方法是在其自身中定义的。foo对这个方法一无所知,即使它确实存在,它也会被子级中的减速覆盖。
对于第四个,我们再次得到barthis 的值,因为即使使用后期静态绑定,我们也会提取相同的数据,bar因为它的值bar是我们实例化的类,所以在运行时,属性中定义的值就是该值。
所以最后两个值是相同的,这是因为 self 和 static 解析相同的信息,无论它们何时被调用。
这可能会让人非常困惑,所以希望它是有道理的。另外,正如我所展示的,不要害怕创建一些像这样的简单类并测试您获得的值。我就是这样学习的。
您提到使用静态调用被认为是不好的。
我认为其中大部分来自依赖性问题。这是类名和代码之间的紧密耦合。使用实例时,将其分配给变量并在调用 new 时使用该名称 1 次。调用 static 时,每次都使用类名。这导致的问题是如果您决定重命名该类。对于实例调用,您只需替换调用 new 的名称,而对于静态调用,则必须在所有地方替换它。
例如考虑这个。
$foo = new foo;
$foo->one();
$foo->two();
//say you inject this into another class
$foo->three();
Run Code Online (Sandbox Code Playgroud)
并将其与此进行比较。
foo::one();
foo::two();
//say you inject this into another class
foo::three();
Run Code Online (Sandbox Code Playgroud)
现在假设您更改了类名。对于第一个,您必须将其替换在一个地方。对于第二个,您必须在每个使用它的地方更换它。您可以通过使用字符串变量来解决这个问题。
$class = 'foo';
$class::one();
$class::two();
//say you inject this into another class
$class::three();
Run Code Online (Sandbox Code Playgroud)
但这样你也会遇到很多麻烦,因为大多数 IDE 无法解析类并进行自动完成。
另外,如果您对其他类的输入进行类型提示
class other{
public method inject(foo $foo){}
}
Run Code Online (Sandbox Code Playgroud)
这在静态类上效果不太好,因为你要传入一个字符串(类名)。
命名空间可能是一个问题。使用实例化,您只需将 use 语句放在实例化类的文件中。使用静态,您必须将它放在任何地方,或者将其包含在每次调用中。
\mystuff\foo::bar();
$foo = '\\mystuff\\foo';
$foo::bar();
Run Code Online (Sandbox Code Playgroud)
我确信还有其他原因,但对我来说这些是主要原因。