取消定义方法或备选方案


Undefining a method or alternative

有了这个插件系统,就有了一个实用程序和一个驱动程序。驱动程序扩展了实用程序,但是,有些驱动程序支持不同的功能,有些不支持某些功能。

我的课应该是这样的:

Class Utility {
  public function MethodOne() {
    # default MethodOne
  }
  public function MethodTwo() {
    # default MethodTwo
  }
}
class Driver extends Utility {
  # MethodTwo not supported in this driver
}

定义方法的简单之处在于,它允许使用该类的开发人员运行method_exists调用,以查看驱动程序是否支持该方法。

有可能在扩展类中对方法进行取消定义吗?或者有一个好的替代方案吗?

在面向对象的语言中,通常无法更改一种方法,如果不是为了扩大它。

但是,尽管PHP不支持用经典继承来限制方法的可见性,但事实证明,当涉及到特性时,它是允许的。

<?php
trait Utility {
    public function methodOne() {
    }
    public function methodTwo() {
    }
}
class Driver {
    use Utility;
    protected function methodTwo(){
    }
}

我们来了:

php > $driver = new Driver;
php > $driver->methodTwo();
PHP Fatal error:  Call to protected method Driver::methodTwo() from context '' in php shell code on line 1

警告:

无论可见性如何,method_exists都将返回true。您必须使用is_callable:

php > var_dump(is_callable([$driver, 'methodOne']));
bool(true)
php > var_dump(is_callable([$driver, 'methodTwo']));
bool(false)

祝你的项目好运!

不能在子函数中取消父函数的定义,而且这不是使用继承的好方法。任何子类都应该能够使用所有的父函数。(否则,为什么要麻烦扩展?)

另一种解决方案是只在每个特定的驱动程序中定义所需的功能,而Utility只包含所有驱动程序都可以使用的通用功能(这是最简单的),然后在驱动程序内部定义特定于驱动程序的功能。

Class Utility {
    public function MethodOne() {
        # default MethodOne
    }
    public function MethodTwo() {
        # default MethodTwo
    }
}
class Driver extends Utility {
    public function MethodThree() {
    }
}
class Driver2 extends Utility {
    public function MethodFour() {
    }
}

这表明Driver和Driver2具有彼此不同的实现功能,同时仍然具有Utility中可用的方法。

最后的解决方案(如果你想强制函数在驱动程序中,否则会抛出错误)是实现多个接口,每个接口将一些函数捆绑在一起:

Class Utility {
    public function MethodOne() {
        print "MethodOne";
    }
    public function MethodTwo() {
        print "MethodTwo";
    }
}
interface inter1 {
    public function MethodThree();
}
interface inter2 {
    public function MethodFour();
}
class Driver extends Utility implements inter1 {
    public function MethodThree(){
        print "MethodThree";
    }    
}
class Driver2 extends Utility implements inter2 {
    public function MethodFour() {
        print "MethodFour";
    }
}

两种解决方案都实现了相同的目的,但Driver必须在接口解决方案中实现MethodThree:

$d = new Driver();
print "Methods for Driver:'n";
foreach (array("MethodOne","MethodTwo","MethodThree","MethodFour") as $k) {
    $p = method_exists($d, $k) ? 'true' : 'false';
    print "'t ".$k.": " . $p ."'n";
}
$d = new Driver2();
print "Methods for Driver2:'n";
foreach (array("MethodOne","MethodTwo","MethodThree","MethodFour") as $k) {
    $p = method_exists($d, $k) ? 'true' : 'false';
    print "'t ".$k.": " . $p ."'n";
}

哪个输出:

Methods for Driver:
    MethodOne: true
     MethodTwo: true
     MethodThree: true
     MethodFour: false
Methods for Driver2:
    MethodOne: true
     MethodTwo: true
     MethodThree: false
     MethodFour: true

如果你想让Driver2有MethodThree,那么你会写:

class Driver2 extends Utility implements inter2, inter1 {
    public function MethodFour() {
        print "MethodFour";
    }
    public function MethodThree() {
    }
}

这个怎么样:

<?php
class Utility{
    //will hold unimplemented methods foor every child
    protected $unimplementedMethods = array();
    protected function f1(){
        //debug
        echo __FUNCTION__ . "'n";
    }
    protected function f2(){
        //debug
        echo __FUNCTION__ . "'n";
    }
    //intercept the functions
    public function __call($name, $arguments)
    {
        if (method_exists($this,$name) && !in_array($name, $this->unimplementedMethods)){
            echo "Calling method: '$name''n";
            $this->$name();
        }
        else{
            //return error or throw exception
            echo "Method: '$name' is not implemented for this driver'n";
        }
    }
}
//driver1
class Driver1 extends Utility{
    //set your non-implemented methods
    protected $unimplementedMethods = array ('f2');
}
//driver2
class Driver2 extends Utility{
    //set your non-implemented methods
    protected $unimplementedMethods = array ('f1');
}
//init
$d1 = new Driver1();
$d2 = new Driver2();

$d1->f1(); //the ok method
$d1->f2(); //the nok method

$d2->f1(); //the nok method
$d2->f2(); //the ok method  
?>

输出:

Calling method: 'f1'
Method: 'f2' is not implemented for this driver
Method: 'f1' is not implemented for this driver
Calling method: 'f2'