Wednesday, December 29, 2010

PHP "Functors" and the __invoke method

 Imagine you have some method of a class that receives as a parameter a function, maybe a callback. You could use one of the new "Closures" available in PHP 5.3, but that way you woudn't have any kind of type hinting or make the code reusable. Why don't we try using something called Functor.



From wikipedia:
"A function object, also called a functor, functional, or functionoid,[1] is a computer programming construct allowing an object to be invoked or called as though it were an ordinary function, usually with the same syntax."
This is exactly why PHP 5.3 has the new magic method __invoke. From the PHP documentation:
"The __invoke method is called when a script tries to call an object as a function."

Bare with me with the totally uselless following code snipet, which will serve to demonstrate how to use Functors. First we create an abstract superclass for the operations:


abstract class AbstractMathOperation {
    /**
     * @var integer
     */
    protected $_counter;
    /**
     * @param integer $startAt
     */
    public function  __construct( $startAt = 0 ) {
        $this->_counter = $startAt;
    }
    /**
     * @return string
     */
    public function  __toString() {
        return (string) $this->_counter;
    }
}

Next the subclasses of AbstractMathOperation:



class Adder extends AbstractMathOperation {
    /**
     * @param integer $toAdd
     * @return integer
     */
    public function __invoke( $toAdd ) {
        return $this->_counter += $toAdd;
    }
}
class Square extends AbstractMathOperation {
    /**
     * @param integer $base
     * @return integer
     */
    public function __invoke( $base ) {
        return $this->_counter = $base * $base;
    }
}

And then how to use them:



class UselessMathClass {

    public static function performOperation( AbstractMathOperation $operMethod, $num ) {
        return $operMethod($num);
    }
}

$Adder = new Adder;
$Square = new Square;

print UselessMathClass::performOperation(
        $Adder, UselessMathClass::performOperation(
                $Square, UselessMathClass::performOperation($Adder, 3)
        )
);


This way you'll have better control on the type of callback you pass as parameter.

No comments: