PHP/OOP method overriding the DRY way

前端 未结 4 488
梦如初夏
梦如初夏 2021-01-14 10:15

I\'m curious if there is a \"better\" design for the following behavior:



        
4条回答
  •  耶瑟儿~
    2021-01-14 10:47

    I found a better general way avoiding closures and other ugly tricks.

    class A {
        /**************************************************************/
        // Chain caller helpers, defined in base class only 
        // (single point of maintenance)
    
        protected $_chain_params; 
    
        final public function chain_call($method_name, $params){
            $class = get_class($this);  // get last child classname
            $chain = array($class);
    
            while ($class !== 'A'){    // get all parents classname
                $class = get_parent_class($class);
                $chain[] = $class;
            }
    
                // Call reversed chain
            $this->_chain_params = $params;
            for ($k = count($chain) - 1; $k >= 0; $k--){
                $class = $chain[$k];
                $refl = new \ReflectionMethod($class, $method_name);
                if ($refl->class === $class)
                    $ret = call_user_func_array(array($this, 
                                                      $class.'::'.$method_name), 
                                                      $this->_chain_params);
            }
            return $ret;
        }
    
        final protected function chain_modify_params($params){
            $this->_chain_params = $params;
        }
        /*************************************************************/
    
        // Methods overrided by child classes:
        public function foo($a, $b){
            echo "A foo fired with params a=$a b=$b 
    "; } protected function bar($a, &$b){ echo "A bar fired with params a=$a b=$b
    "; return 1000; } } // Child classes extending base class. NOTE: no need to smell the code! class B extends A { public function foo($a, $b){ echo "B foo fired with params a=$a b=$b
    "; } protected function bar($a, &$b){ echo "B bar fired with params a=$a b=$b
    "; return 2000; } } class C extends B { public function foo($a, $b){ echo "C foo fired with params a=$a b=$b
    "; } protected function bar($a, &$b){ echo "C bar fired with params a=$a b=$b
    "; $a++; // override param value $b++; // override referenced param value echo " - C modify => a=$a b=$b
    "; // reflect changed parameters to the next child class in chain ;) $this->chain_modify_params(array($a, &$b)); return 3000; } } class D extends C { public function foo($a, $b){ echo "D foo fired with params a=$a b=$b
    "; } protected function bar($a, &$b){ echo "D bar fired with params a=$a b=$b
    "; return 4000; } } $d = new D(); echo 'Call "foo" directly...
    '; $d->foo(10, 20); echo '
    Call "foo" in chain mode...
    '; $d->chain_call('foo', array(10, 20)); echo '
    More complex example: call "bar" in chain mode,'. 'passing $k by reference, '. 'and getting last method result...

    '; $k = 40; $ret = $d->chain_call('bar', array(30, &$k)); echo "
    D->bar() return: " . $ret; echo "
    k = $k";

    Result:

    Call "foo" directly... 
    D foo fired with params a=10 b=20 
    
    Call "foo" in chain mode... 
    A foo fired with params a=10 b=20 
    B foo fired with params a=10 b=20 
    C foo fired with params a=10 b=20 
    D foo fired with params a=10 b=20 
    
    More complex example: call "bar" in chain mode, 
    passing $k by reference, and getting last method result... 
    
    A bar fired with params a=30 b=40 
    B bar fired with params a=30 b=40 
    C bar fired with params a=30 b=40 
     - C modify => a=31 b=41 
    D bar fired with params a=31 b=41 
    
    D->bar() return: 4000
    k = 41
    

提交回复
热议问题