【问题标题】:Undefining a method or alternative取消定义方法或替代方法
【发布时间】:2015-03-03 19:12:50
【问题描述】:

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

我的课会是这样的:

Class Utility {

  public function MethodOne() {
    # default MethodOne
  }

  public function MethodTwo() {
    # default MethodTwo
  }

}

class Driver extends Utility {
  # MethodTwo not supported in this driver
}

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

是否可以取消定义扩展类中的方法或有更好的选择?

【问题讨论】:

  • 为什么不在实用程序中只包含常用方法,让每个驱动程序定义自己的额外方法?在您的情况下,继承有什么意义。
  • @amrhady:这不允许以后进行更改。如果有人添加了不支持某个功能的新驱动程序,那么您必须返回并可能更改所有其他类。
  • 但这正是我的观点。这与继承相反,您正在使用继承来解决它。
  • 继承是因为大部分功能在驱动程序之间共享。但是一些驱动程序,尤其是新驱动程序,还没有内置的所有功能。因此,如果有人想使用一个新的驱动程序还没有支持的功能(或者可能永远),他们要么需要在该类中定义所有常用功能而不扩展实用程序,要么他们需要返回并从实用程序中删除不支持的功能,然后在每个支持它的驱动程序中添加该功能。即使它限制了添加新驱动程序的便利性。

标签: php oop methods


【解决方案1】:

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

虽然 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)

祝你的项目好运!

【讨论】:

  • 谢谢!看起来不错,无论如何 is_callable 可能比 method_exists 更好。感谢您的帮助。
【解决方案2】:

您不能取消定义子函数中的父函数,这不是使用继承的好方法。任何子类都应该能够使用所有父函数。 (否则,为什么还要延长?)

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

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

【讨论】:

  • 感谢您的来信。像这样的接口可能会变得混乱,因为我们在一个类中讨论多达 100 个函数,并且不知道所有驱动程序都支持什么功能,特别是考虑到以后可能会添加可能不支持某个功能的新驱动程序。因此,在这种情况下,我将不得不返回并编辑每个其他类以实现兼容性。 (从 Utility 中删除该功能并将接口添加到每个其他驱动程序)
  • 感觉最好的方法是用抛出 BadMethodCallException 的东西覆盖父函数,然后有一个数组 $not_implemented 的 Utility 部分被每个驱动程序覆盖,然后你会添加所有尚未完成的函数,并有一个函数 get_defined_functions() { return method_exists($this, "method") && !in_array("method", $not_implemented); }
  • 是的,看起来是这样。我会给你一个赞成票,因为你的回答可能会帮助遇到这个问题的其他人。
【解决方案3】:

这个怎么样:

<?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'

【讨论】:

  • 看起来是个不错的选择 +1。您可以像 MasterOdin 建议的那样在 __call() 中合并一个异常。不适用于 method_exists 但这似乎是不可能的。
猜你喜欢
  • 2011-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-05
  • 2012-08-21
  • 2012-11-08
  • 2019-04-27
  • 2012-09-25
相关资源
最近更新 更多