【问题标题】:Overriding methods in PHP?PHP中的覆盖方法?
【发布时间】:2012-12-03 08:15:28
【问题描述】:

在 Java 等其他 OO 语言中,我们可以覆盖函数,可以使用 implements@override 等关键字/注解。

有没有办法在 PHP 中做到这一点?我的意思是,例如:

class myClass {
    public static function reImplmentThis() { //this method should be overriden by user
    }
}

我希望用户实现自己的myClass::reImplementThis() 方法。

我怎样才能在 PHP 中做到这一点?如果可能,我可以将其设为可选吗?

我的意思是,如果用户没有实现该方法,我可以指定一个默认方法还是可以识别该方法未定义(我可以使用method_exists 来执行此操作)吗?

【问题讨论】:

  • 一般来说,我会让它成为非静态的,然后用户可以扩展 myClass - 选择是否重新定义reImplmentThis()。如果您的默认实现是可接受的,则无需测试用户实现是否存在。
  • 您可以使用和抽象类来扩展(如halfer 所说)和接口类(killerphp.com/articles/php-interfaces)以确保最终类至少具有您指定的功能。我只是在学习这些(接口)我可能是错的,但从我所读到的内容来看,这似乎是拥有它们的原因。

标签: php oop overriding implements


【解决方案1】:

这涉及到几个 OOP 主题。

首先,简单地覆盖父类中声明的方法就像在继承类中重新声明该方法一样简单。

例如:

class Person {

    public function greet(string $whom) {
        echo "hello $whom!";
    }

}

class Tommy extends Person {
    public function greet(string $whom = "everyone") {
        echo "Howdy $whom! How are you?";
    }
}

$a = new Tommy();
$a->greet('World');

// outputs:
// Howdy World! How are you?

如果在覆盖方法上你想重用被覆盖方法的逻辑,只需从扩展类调用父方法::

class Tommy
{
    public function greet(string $whom)
    {
        // now with more emphasis!!!
        echo parent::greet(strtoupper($whom)) . "!!!!";
    }
}

现在Tommy::greet() 调用Person::greet(),但在返回之前修改了结果。

需要注意的一点是,覆盖方法必须与被覆盖的方法兼容:方法可见性不能比原来的限制性更强(增加可见性就可以了),以及的数量和类型required 参数不能与原始声明冲突。

这是可行的,因为参数的类型与原始参数没有冲突,而且我们需要的参数比父级上的要少

class Leo extends Person {
    public function greet(string $whom = "gorgeous", string $greet = "Whatsup" ) {
        echo "$greet $whom. How are you?";
    }
}

但这没有,因为还有额外的必需参数。这将无法透明地切换原始类,因此会抛出Warning


class BadBob extends Person {
    public function greet(string $whom, string $greet ) {
        echo "$greet $whom. How are you?";
    }
}

此外,您在问题中提到“此方法应由用户覆盖”。如果您需要客户端类来实际实现该方法,您有两种选择:

抽象类和方法

这些方法的实现为空,扩展类必须实现才有效。在我们将原来的类 Person 更改为:

abstract class Person {

    public function greet(string $whom) {
        echo "hello $whom!";
    }

    public abstract function hide();

}
  • 由于现在该类包含抽象方法,因此也需要将其声明为抽象类。
  • 现在不能直接实例化Person,只能在其他类中扩展。
  • 现在我们所有现有的 Person 扩展类都会出错,尝试执行之前的代码会引发致命错误。

现在扩展 Person 的有效类的示例是:

class Archie extends Person {

    public function hide() {
        echo "Hides behind a bush";
    }
}

任何扩展Person的类必须声明一个公共的hide()方法。

接口

最后,您提到了接口。接口是实现类必须履行的契约。他们声明了一组公共方法没有实现主体

例如:


interface Policeman {
    public function arrest(Person $person) : bool;
        
    public function help($what): bool;
}

现在我们可以拥有扩展 Person 并实现 Policeman 的类:

class Jane extends Person implements Policeman {
    
    public function hide() {
        echo "Jane hides in her patrol-car";
    }
    
    public function arrest(Person $person): bool{
        // implement arrest method
        
        return false;
    }
    
    public function shoot($what): bool {
        // implements shoot() method
        
        return false;
    }
}

重要的是,虽然可以仅扩展 一个 类(PHP 中没有多重继承),但可以实现多个接口,并且必须满足每个接口的要求类是有效的。

【讨论】:

    【解决方案2】:

    是的,有。您可以选择通过扩展类并定义具有与基类中相同的名称、函数签名和访问说明符(公共或受保护)的方法来覆盖方法。该方法不应在基类中声明为抽象的,否则您将需要在派生类中实现它。在您的示例中,它看起来像这样:

    class MyClass {
        public static function reImplmentThis() { //this method should be overriden by user
        }
    }
    
    class MyDerivedClass extends MyClass {
        public static function reImplmentThis() { //the method you want to call
        }
    }
    

    如果用户不重写它,MyDerivedClass 仍然有一个 reImplmentThis() 方法,该方法继承自 MyClass。

    也就是说,在从派生类调用扩展静态方法时需要非常小心,以免遇到麻烦。我鼓励您重构代码以扩展实例方法,除非您非常需要扩展静态类。如果您认为没有比扩展静态类更好的方法,请务必非常了解Late Static Binding

    是的,可以使用PHP Reflection 来检查方法是否已实现,并获取有关类的更多信息。

    【讨论】:

      【解决方案3】:
      <?php
      abstract class Test
      {
          abstract protected function test();
      
          protected function anotherTest() {
      
          }
      }
      
      class TestTest extends Test
      {
          protected function test() {
      
          }
      }
      
      $test = new TestTest();
      ?>
      

      这样,TestTest 类必须覆盖函数 test。

      【讨论】:

      • 在 OP 的情况下,reImplementThis() 将被声明为非抽象的,因为默认实现是可以的。但是,是的,+1。
      • @Dillen 这不是用户提出的问题的答案,这只是应该如何完成的变体,但不满足用户的要求
      猜你喜欢
      • 2021-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-23
      • 1970-01-01
      • 1970-01-01
      • 2012-12-07
      相关资源
      最近更新 更多