【问题标题】:PHP Abstract Classes w/ Common Methods: How to call带有通用方法的 PHP 抽象类:如何调用
【发布时间】:2013-09-13 20:48:08
【问题描述】:

我对在抽象类中调用常用方法的正确方法有点困惑。使用以下代码:

abstract class Transaction {

    abstract public function process();
    abstract public function set_status();

    protected function get_valid_statuses() {
        return array(
            'pending',
            'approved'
        );
    }

}

class Purchase extends Transaction {

     public function process() {
     }

     public function set_status( $status ) {

          //check against valid statuses
          $valid = Transaction::get_valid_statuses();

          .......

     }

}

显然,这段代码还远未完成,但对于本示例来说应该足够了。我想知道为什么会这样,因为我已经测试过了。在我的 Purchase 类中,当使用 set_status 方法时,我使用通常用于静态方法的范围解析运算符调用 get_valid_statuses() 方法。我会假设使用以下方法调用该方法:

$valid = Transaction->get_valid_statuses();

但我想这不会起作用,因为该类从未实际实例化。有人可以提供一些澄清。我无法从 PHP 文档中找到关于抽象类或范围解析运算符的理解。

谢谢!

【问题讨论】:

  • $this->get_valid_statuses() 来自扩展类。 parent::get_valid_statuses() 如果你重载了它。
  • 说的有道理,但是为什么上面的方法有效呢?

标签: php oop abstract-class static-methods


【解决方案1】:

打开错误报告,您将看到 Strict 错误:

非静态方法 Transaction ::get_valid_statuses() 不应静态调用

这个错误出现在所有 5.x php 版本中——所以它确实是出于向后兼容性的原因。回到 php4 的黑暗时期,没有办法在类中声明静态方法,所以所有方法都被简单地声明为 function foo(){ }

您可以了解静态方法here。简单来说,调用这个方法之前不需要实例化类(因为abstract关键字不能实例化),而是通过类名和作用域解析操作符来调用。

这也有效,因为在此方法中没有对当前对象 ($this) 的引用。如果您更改此方法主体以使用$this 引用其属性/方法之一,您将出现致命错误。

【讨论】:

  • 这是有道理的,但我正在运行 PHP 5+ 并且有错误报告。仍然没有错误/警告。无论哪种方式,我都将其修改为 $this->....
  • 默认错误报告设置不包括严格错误,使用error_reporting(-1)(不是E_ALL)查看所有可能的错误
【解决方案2】:

抽象类不能被实例化,但方法(非抽象)可以作为静态方法调用。
无论如何,这是非常糟糕的代码风格 - 请考虑不要使用它。

【讨论】:

  • 这里没有静态方法。你的回答无效。在这种情况下使用抽象类也不错。
  • @Sven 静态调用非静态方法是不好的做法,而不是在抽象类上调用它
【解决方案3】:

该方法不是静态的,因此您不应使用静态方法运算符 (::)。也因为Purchase继承了抽象类,它会自动获取它的所有方法,可以使用$this

$valid = $this->get_valid_statuses();

【讨论】:

  • 这个我明白,但我不明白为什么静态方法运算符 (::) 有效。
  • @克里斯啊。它之所以有效,是因为该方法不是抽象的(只有类是抽象的,这意味着它不能被实例化)。我相信在静态调用非静态方法时,您应该会收到“已弃用”错误(或类似错误)。它曾经被允许,但前一段时间已被弃用。尝试将error_reporting(-1); 放在脚本的顶部。
【解决方案4】:

使用 :: 运算符(范围解析运算符)并不总是触发 STATIC 方法调用。

在你的情况下,确实如此。您正在使用类名。但是有一些特殊的关键字不会触发静态调用:selfparentstatic

除此之外,还有一个引用当前自己对象的变量:$this

因此,无论何时你继承一个类并带来它自己的方法,你总是可以像对待它们在你当前的类中一样对待它们,并调用$this->get_valid_statuses()。这会动态检查当前类中是否存在该函数,或者按降序排列任何父类或父父类,并调用找到的第一个。

如果要确保调用父类的函数,请使用parent::get_valid_statuses()。如果要确保调用 CURRENT 类的方法,请使用self::get_valid_statuses()

static 关键字在继承类中的静态方法时起着重要作用 - 但由于静态方法通常比帮助你更邪恶,我只想指出 manual

继承类的时候怎么办?这取决于。 $this 有效。它还允许在当前类中覆盖 get_valid_statuses() 并对其进行扩展。

parent::get_valid_statuses() 只有在您的 Purchase 类覆盖 get_valid_statuses() 并希望从父类获取状态时才应该调用。在这种情况下,您不能调用$this->get_valid_statuses(),因为这将再次调用同一类中的方法,从而导致一个永无止境的循环。所以parent::$this->是最常用的前缀。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-21
    • 2011-08-14
    • 1970-01-01
    • 2017-05-02
    • 2023-03-07
    相关资源
    最近更新 更多