【问题标题】:Instance vs. static method. Calling it statically or dynamically实例与静态方法。静态或动态调用它
【发布时间】:2018-09-10 09:06:39
【问题描述】:

PHP中有实例方法和静态方法(就这两种)?那么我们可以静态或非静态地调用其中任何一个(名称是“动态”吗?)?

所以我们可以:

  1. 静态调用实例方法;
  2. 非静态调用实例方法;
  3. 静态调用静态方法;
  4. 非静态调用静态方法(四个都正确?)

这四个的代码看起来如何?有什么好的网站可以解释这个吗?我目前正在阅读以下网址:

http://php.net/manual/en/language.oop5.basic.php

...我不明白这一点:

"$this 是对调用对象的引用(通常是方法所属的对象,但也可能是另一个对象,如果该方法是从辅助对象的上下文中静态调用的)。"

代码将如何查找从辅助对象静态调用方法?我的意思是,静态调用与非静态调用,这是什么?

【问题讨论】:

  • 关于“代码如何查找从辅助对象静态调用方法?”,请阅读文档中的示例“示例#2 $this 伪变量的一些示例” .
  • 所以在示例 #2 中,B 类是次要对象,这是从该对象静态调用方法 -> “A::foo();”? “静态调用”可以通过“::”符号识别?
  • 是的。打扰一下,但我认为您对静态/动态的解读有点过多。命名可能会使您感到困惑。在我看来,最好使用 Ruby 术语并将静态方法称为 类方法,将常用方法称为 实例方法。它有助于更​​好地理解差异。
  • 我正在阅读 php.net 手册,并试图了解其中的内容。我只学习 PHP,还不熟悉 Ruby。基本上我想弄清楚最基本的事情并从那里开始。就像有实例和静态方法(只有这两种类型)。然后你可以静态地和非静态地调用这些中的任何一个,依此类推。在我弄清楚(我不确定的“知识骨架”)之后,我可以从那里开始。另外,如果静态调用可以转换为使用“::”(所以我可以通过这个识别它)。

标签: php oop methods static non-static


【解决方案1】:

你不应该静态调用非静态方法。

一些例子

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 时)
  • 子级可以更改父级中访问的静态属性(使用静态、后期静态绑定时)

现在,如果您想要确切的答案:

  1. 静态调用实例方法;
    • 你可以但不应该,因为 $this 不存在
  2. 非静态调用实例方法;
    • 这是正常的
  3. 静态调用静态方法;
    • 这也是正常的
  4. 非静态调用静态方法(四个都正确?)
    • 无论范围如何,确保静态可用

我们可以使用上面的类来举例说明

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
(
)

所以我想给你一个关于selfstatic 的简单例子,这真的很令人困惑。

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 解析类时解析的。

  • barfoo 的孩子。
  • 我们实例化孩子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();

我确信还有其他原因,但对我来说这些是主要原因。

【讨论】:

  • 您能回答我的确切问题吗?我不了解这方面的内容。我知道在 PHP 5.3.0 中静态调用非静态方法会发出错误,现在情况甚至不同了。
  • 我从来没有考虑过使用静态方法,因为我听说它们是“邪恶的”......我从中看到的是它允许您访问一个方法,就好像它只是一个普通的旧方法函数(名称中带有双冒号)。但显然,它不仅仅是编写Foo::biz() 而不是(new Foo)-&gt;biz() 的简单性。我得消化一下你的回答。 :)
【解决方案2】:

我们看下面的代码:

<?php

class A
{
    public $property = "property A";

    public function testA()
    {
        echo "class A ";
        echo $this->property;
    }
}

class B
{
    public $property = "property B";

    public function testB()
    {
        A::testA();
    }
}

$b = new B;
$b->testB();

它将显示class A property B

您正在使用B 访问A 类中的属性$this。 这不适用于 PHP 7+,您将在 PHP 5.6 上收到以下警告:

WARNING Non-static method A::testA() should not be called statically, assuming $this from incompatible context on line number 16

它“有效”,但您不应该从静态上下文调用非静态方法。

【讨论】:

  • 感谢您的回答。一般来说,只有静态和实例方法(只有这两种类型)?然后我们可以静态和非静态地处理所有这些吗?使用“::”符号表示静态调用?这些都是我不明白的。
  • 是的。静态意味着您不需要对象实例($var = new Class)。您可以从类中调用它(Class::method)。当您需要状态时使用对象,等等。当你只做简单的事情而不需要状态时,你可以使用静态方法。
  • @ThomasMorgan - 还有Magic 方法,您已经使用过这些方法,例如__construct(),但还有更多……有趣的事情。但这完全是另一个话题。
猜你喜欢
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多