PHP强制函数调用

Posted

技术标签:

【中文标题】PHP强制函数调用【英文标题】:PHP mandatory function call 【发布时间】:2013-03-02 00:18:03 【问题描述】:

我知道可以使用接口来强制定义函数,但我找不到可以强制调用函数的东西,例如如果我使用函数创建一个作为另一个类成员的类(通过扩展等),则该类会自动确保使用该函数部分调用强制函数。

我的意思是,进一步澄清:

class domain 

   function isEmpty($input) 
      //apply conditional logic and results
   

class test extends domain 

   function addTestToDBTable($test) 
      /** 
       *  try to add but this class automatically makes it so that all rules of
       *  class domain must be passed before it can run
       *  - so essentially, I am no longer required to call those tests for each and
       *    every method 
       **/  
   
 

如果这看起来不连贯,我们深表歉意。当然,这似乎很懒,但我希望能够强制上下文而不必担心

更新:

好的,进一步澄清:在 php 中,如果我为子类扩展并声明 __construct(),则该子类将覆盖父类 __construct()。我不希望这样,我希望父构造保留下来,并随心所欲地授权,就像子类也可以这样做一样。

【问题讨论】:

你是指接口还是抽象类? 也许你可以在domain 中创建一个addTestToDBTable(或其他函数名),然后使用parent::addTestToDBTable() 我的意思是,例如,如果没有应用规则,我希望它自动输出错误——我希望强制执行规则,而不必将其应用于每个单独的函数。我希望该超类自动强制执行这些规则(例如默认或自定义集)。 @user784446 我认为这就是单元测试的目的。 @Rocket Hazmat,我明白,但我的意思是我什至不想这样做。我希望域自动处理所有这些东西。很简单,即使应用于域的上下文,测试也应该只关心自己——除非我另有说明。该类的每个函数都不应该有任何与域有关的显式代码,因此 addTestToDBTable 只是有它的逻辑。因为类测试是域的成员,域通过强制规则来管理它。 【参考方案1】:

我想这可以通过两种不同的方式完成。

面向方面的编程

看看这里https://github.com/AOP-PHP/AOP

生成或编写代理类

一个非常简单的例子可能是:

<?php
class A 
    public function callMe() 
        echo __METHOD__ . "\n";
    


class B extends A 

    // prevents instantiation
    public function __construct() 
    

    public function shouldCallMe() 
        echo __METHOD__ . "\n";
    

    public static function newInstance() 
        return new ABProxy();
    


class ABProxy 
    private $b;

    public function __construct() 
        $this->b = new B();
    

    public function __call($method, $args) 
        $this->b->callMe();
        return call_user_func_array(array($this->b, $method), $args);
    


// make the call
$b = B::newInstance();
$b->shouldCallMe();

// Outputs
// ------------------
// A::callMe
// B::shouldCallMe

希望这会有所帮助。

【讨论】:

【参考方案2】:

听起来你想要一个Decorator

请参阅 This answer 了解如何操作的详细说明。请注意,它不需要类扩展。

【讨论】:

【参考方案3】:

我会使用带有一些文档块元编程魔法的域验证装饰器。但这确实是整个图书馆的工作,毫无疑问是存在的。

fiddle

<?php
class FooDomain 
    public static function is_not_empty($input) 
        return !empty($input);
    


class Foo 
    /**
     * @domain FooDomain::is_not_empty my_string
     */
    public function print_string($my_string) 
        echo $my_string . PHP_EOL;
    


$foo = new DomainValidator(new Foo());
$foo->print_string('Hello, world!');
try 
    $foo->print_string(''); // throws a DomainException
 catch (\DomainException $e) 
    echo 'Could not print an empty string...' . PHP_EOL;


// ---

class DomainValidator 
    const DOMAIN_TAG = '@domain';

    private $object;

    public function __construct($object) 
        $this->object = $object;
    

    public function __call($function, $arguments) 
        if (!$this->verify_domain($function, $arguments)) 
            throw new \DomainException('Bad domain!');
        

        return call_user_func_array(
            array($this->object, $function),
            $arguments
        );
    

    public function __get($name) 
        return $this->object->name;
    

    public function __set($name, $value) 
        $this->object->name = $value;
    

    private function verify_domain($function, $arguments) 
        // Get reference to method
        $method = new \ReflectionMethod($this->object, $function);
        $domains = $this->get_domains($method->getDocComment());
        $arguments = $this->parse_arguments(
            $method->getParameters(),
            $arguments
        );
        foreach ($domains as $domain) 
            if (!call_user_func(
                $domain['name'],
                $arguments[$domain['parameter']]
            )) 
                return false;
            
        
        return true;
    

    private function get_domains($doc_block) 
        $lines = explode("\n", $doc_block);
        $domains = array();
        $domain_tag = DomainValidator::DOMAIN_TAG . ' ';
        foreach ($lines as $line) 
            $has_domain = stristr($line, $domain_tag) !== false;
            if ($has_domain) 
                $domain_info = explode($domain_tag, $line);
                $domain_info = explode(' ', $domain_info[1]);
                $domains[] = array(
                    'name'      => $domain_info[0],
                    'parameter' => $domain_info[1],
                );
            
        
        return $domains;
    

    private function parse_arguments($parameters, $values) 
        $ret = array();
        for ($i = 0, $size = sizeof($values); $i < $size; $i++) 
            $ret[$parameters[$i]->name] = $values[$i];
        
        return $ret;
    

输出:

Hello, world!
Could not print an empty string...

【讨论】:

抱歉,我必须更彻底地阅读。但是,我已经更深入地考虑了它,父类必须能够“知道”子类的方法,或者子类必须能够“知道”它自己的方法(即对于构造函数来注册其方法)。我真的不知道该怎么做。 @user784446 PHP 有反射,但速度很慢,所以我不会在生产过程中使用它。您可以通过making a \ReflectionClass 和调用its getMethods method 获取类的方法。真正的问题是不可能拦截所有方法调用(只有那些不存在的方法调用),所以你要么必须将所有方法设为私有,要么必须使用装饰器。 @walheed khan 我可以使用 get_class_methods($class) 但仍然存在类构造的问题。 @user784446 如果父类和子类都知道子类的方法,问题出在哪里?

以上是关于PHP强制函数调用的主要内容,如果未能解决你的问题,请参考以下文章

强制调用基类虚函数

php函数中,多个参数的情况下怎么使其中一个参数为默认值而其他的使用指定值

iOS Swift Parse-强制退出应用程序后调用解析云函数

PyQT 在调用其他函数之前强制更新 textEdit

重载时如何强制matlab调用常规函数而不是类方法?

强制 R 在 set_args 函数的参数内应用函数或调用变量