6

this is my class:

class toyota extends car {
    function drive() {
    }
    function break() {
    }
}

class car {
    function pre() {
    }
}

Is there any way I can do so that when I run $car->drive(), $car->break() (or any other function in toyota), it would call $car->pre() first before calling the functions in toyota?

2
  • Read up on "constructor" functions...that may be what you need. Commented Mar 28, 2012 at 4:38
  • Can you please clarify? I can't tell if you want to run $car->pre() whenever you create a new object, or anytime you call a method of $car. The answers below cover both - I just don't know which one to mod up. Commented Mar 28, 2012 at 4:42

5 Answers 5

14

Yep. You could use protected and some __call magic:

class toyota extends car {
    protected function drive() {
        echo "drive\n";
    }
    protected function dobreak() {
        echo "break\n";
    }
}

class car {
    public function __call($name, $args)
    {
        if (method_exists($this, $name)) {
            $this->pre();
            return call_user_func_array(array($this, $name), $args);
        }


    }

    function pre() {
        echo "pre\n";
    }
}

$car = new toyota();
$car->drive();
$car->dobreak();

http://ideone.com/SGi1g

Sign up to request clarification or add additional context in comments.

9 Comments

Not only is this the only answer that uses __call (the right way to do it) but it also is the only one that actually does some method_exists check and actually calls the originally called method to begin with. Do this!
Do you mean private instead of protected? Cause protected can still be visible by parent and inherited.
@sberry, checking with method_exists() will hide the default error received when calling invalid methods
@Starx: yep, but in case of not existent method you could throw native error or exception
@Patrick: nope, private won't work, because parent class doesn't have an access to the ancestor's private methods
|
1

You could do the following, but I don't think that is what you want.

class toyota extends car {
    function drive() {
         $this->pre();
    }
    function break() {
         $this->pre();
    }
}

class car {
    function pre() {
    }
}

You may want to look into PHP specific magic methods. http://php.net/manual/en/language.oop5.magic.php

Comments

0

This will better done with the magic methods called __call()

public function __call($name, $arguments)
{
    $this -> pre();
    return $this -> $name($arguments);
}

What is this method? It overrides the default method call, so that preCall State can be invoked.

Your toyota class

class toyota extends car {    

    public function __call($name, $arguments)
    {
        $this -> pre();
        return call_user_func_array(array($this, $name), $arguments);
    }

    function drive() {
    }
    function break() {
    }
}

1 Comment

$this -> $name($arguments) --- will call the requested method with all the parameters passed as an array. So $car->drive(1, 2) will be re-called with $car->drive(array(1, 2)) which is just incorrect
0

If you are using PHP5 (>=5.3.2), there is a solution that works with declaring all methods as private. This will enforce method call from single function call:

exec_method()

To run at: http://ideone.com/cvfCXm

The code snippet is here:

<?php

    class car {

        //method to get class method
        public function get_method($method_name) {
            $class = new ReflectionClass(get_class($this));
            $method = $class->getMethod($method_name);
            $method->setAccessible(true);
            return $method;
        }

        public function exec_method($method_name, $arg_args=array()) {

            //execute the pre() function before the specified method
            $this->pre();

            //execute the specified method
            $this->get_method($method_name)->invokeArgs($this, $arg_args);
        }

        public function pre() {
            echo 'pre';
            echo '<br />';
        }
    }

    class toyota extends car {
        private function drive() {
            echo 'drive';
            echo '<br />';
        }

        private function brake() {
            echo 'brake';
            echo '<br />';
        }
    }

    $toyota = new toyota();
    $toyota->exec_method('drive');
    $toyota->exec_method('brake');
?>

Reference:

Answer to Best practices to test protected methods with PHPUnit [closed]

Comments

-2

Just add a constructor, like this...

class toyota extends car {
    function __construct() { 
        $this->pre();
    }   

    function drive() {
        echo "drive!";
    }

    function dobreak() {
        echo "break!";
    }
}

class car {
    function pre() {
        echo "Hello!";
    }
}

$car = new toyota();
$car->drive();
$car->dobreak();

Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.

break is reserved, so you shouldn't use this as a function name.

2 Comments

i think he is looking for a way to run the method pre prior to a function call, not on object initialization
While replying I was interrupted. I've updated my example with the constructor. it still does the job.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.