Last active
February 5, 2017 11:28
-
-
Save wyrfel/633c5f8f4225bd753d01 to your computer and use it in GitHub Desktop.
Callback Helper to extend capabilities of php built-ins that allow passing of custom callback functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Wyrfel\Helper; | |
use Exception; | |
/** | |
* Callback helper | |
* | |
* This allows passing parameters to callbacks for php built-ins that take a callback | |
* parameter without providing the option to specify additional arguments. | |
* | |
* The invocation arguments can be prepended (default) or appended to the | |
* instantiation arguments, they can be ignored altogether or | |
* override the instantiation arguments | |
* | |
* @package Wyrfel\Helper | |
*/ | |
class Callback | |
{ | |
const PREPEND_INVOCATION_ARGS = 1; | |
const APPEND_INVOCATION_ARGS = 2; | |
const IGNORE_INVOCATION_ARGS = 3; | |
const OVERRIDE_INSTANTIATION_ARGS = 4; | |
/** | |
* @var stdClass - the object | |
*/ | |
protected $object; | |
/** | |
* @var string - the method name | |
*/ | |
protected $method; | |
/** | |
* @var array - the arguments | |
*/ | |
protected $arguments; | |
/** | |
* @var int - the argument merge behaviour | |
*/ | |
protected $mode = self::PREPEND_INVOCATION_ARGS; | |
/** | |
* internally stores the object, method name and arguments given | |
* | |
* @param $object - the object | |
* @param string $method - the method name | |
*/ | |
public function __construct($object, $method) | |
{ | |
if (!is_object($object)) { | |
throw new Exception(sprintf('The first parameter to the Callable constructor must be an object, %s given', gettype($object))); | |
} | |
if (!is_string($method)) { | |
throw new Exception(sprintf('The second parameter to the Callable constructor must be a method name, %s given', gettype($method))); | |
} | |
if (!is_callable($object, $method)) { | |
throw new Exception(sprintf('%s::%s is not callable', get_class($object), $method)); | |
} | |
$this->object = $object; | |
$this->method = $method; | |
$this->arguments = array_slice(func_get_args(), 2); | |
} | |
/** | |
* invokes the method on the object with the given arguments | |
*/ | |
public function __invoke() | |
{ | |
$arguments = $this->mergeArguments(func_get_args()); | |
return call_user_func_array(array($this->object, $this->method), $arguments); | |
} | |
/** | |
* sets the invocation behaviour to append invocation arguments | |
* to the instantiation arguments | |
* | |
* @return $this | |
*/ | |
public function appendInvocationArguments() | |
{ | |
$this->mode = self::APPEND_INVOCATION_ARGS; | |
return $this; | |
} | |
/** | |
* sets the invocation behaviour to ignore invocation arguments alltogether | |
* | |
* @return $this | |
*/ | |
public function ignoreInvocationArguments() | |
{ | |
$this->mode = self::IGNORE_INVOCATION_ARGS; | |
return $this; | |
} | |
/** | |
* sets the invocation behaviour to prepend invocation arguments | |
* to the instantiation arguments | |
* | |
* @return $this | |
*/ | |
public function prependInvocationArguments() | |
{ | |
$this->mode = self::PREPEND_INVOCATION_ARGS; | |
return $this; | |
} | |
/** | |
* sets the invocation behaviour to override instantiation arguments | |
* with invocation arguments based on their position | |
* | |
* (the usefulness of this is questionable) | |
* | |
* @return $this | |
*/ | |
public function overrideInstantiationArguments() | |
{ | |
$this->mode = self::OVERRIDE_INSTANTIATION_ARGS; | |
return $this; | |
} | |
/** | |
* merges the invocation arguments with the instantiation arguments | |
* according to the set mode | |
* | |
* @param array $invocationArguments | |
* | |
* @return array | |
*/ | |
protected function mergeArguments(array $invocationArguments) | |
{ | |
if ($this->mode === self::IGNORE_INVOCATION_ARGS) { | |
return $this->arguments; | |
} | |
if ($this->mode === self::APPEND_INVOCATION_ARGS) { | |
return array_merge($this->arguments, $invocationArguments); | |
} | |
if ($this->mode === self::OVERRIDE_INSTANTIATION_ARGS) { | |
$tmp = $this->arguments; | |
foreach ($invocationArguments as $k => $v) { | |
$tmp[$k] = $v; | |
} | |
return $tmp; | |
} | |
return array_merge($invocationArguments, $this->arguments); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Wyrfel\Helper; | |
use PHPUnit_Framework_TestCase; | |
/** | |
* tests the callback helper | |
* | |
* @package Wyrfel\Helper | |
*/ | |
class CallbackTest extends PHPUnit_Framework_TestCase | |
{ | |
const RETURN_VALUE = 'abcd'; | |
/** | |
* tests the default behaviour | |
*/ | |
public function testDefault() | |
{ | |
$object = $this->getMock('Wyrfel\Helper\Callback', array('__invoke'), array(), '', false); | |
$object->expects($this->any()) | |
->method('__invoke') | |
->with('a', 'b', 'c', 'd') | |
->will($this->returnValue(self::RETURN_VALUE)); | |
$callback = new Callback($object, '__invoke', 'c', 'd'); | |
$this->assertSame(self::RETURN_VALUE, $callback('a', 'b')); | |
} | |
/** | |
* tests the prependInvocationArguments behaviour | |
*/ | |
public function testPrepend() | |
{ | |
$object = $this->getMock('Shared\Helper\Callback', array('__invoke'), array(), '', false); | |
$object->expects($this->any()) | |
->method('__invoke') | |
->with('a', 'b', 'c', 'd') | |
->will($this->returnValue(self::RETURN_VALUE)); | |
$callback = new Callback($object, '__invoke', 'c', 'd'); | |
$this->assertSame($callback, $callback->prependInvocationArguments()); | |
$this->assertSame(self::RETURN_VALUE, $callback('a', 'b')); | |
} | |
/** | |
* tests the appendInvocationArguments | |
*/ | |
public function testAppend() | |
{ | |
$object = $this->getMock('Wyrfel\Helper\Callback', array('__invoke'), array(), '', false); | |
$object->expects($this->any()) | |
->method('__invoke') | |
->with('c', 'd', 'a', 'b') | |
->will($this->returnValue(self::RETURN_VALUE)); | |
$callback = new Callback($object, '__invoke', 'c', 'd'); | |
$this->assertSame($callback, $callback->appendInvocationArguments()); | |
$this->assertSame(self::RETURN_VALUE, $callback('a', 'b')); | |
} | |
/** | |
* tests the ignoreInvocationArguments behaviour | |
*/ | |
public function testIgnore() | |
{ | |
$object = $this->getMock('Wyrfel\Helper\Callback', array('__invoke'), array(), '', false); | |
$object->expects($this->any()) | |
->method('__invoke') | |
->with('c', 'd') | |
->will($this->returnValue(self::RETURN_VALUE)); | |
$callback = new Callback($object, '__invoke', 'c', 'd'); | |
$this->assertSame($callback, $callback->appendInvocationArguments()); | |
$this->assertSame(self::RETURN_VALUE, $callback('a', 'b')); | |
} | |
/** | |
* tests the overrideInvocationArguments behaviour | |
*/ | |
public function testOverride() | |
{ | |
$object = $this->getMock('Wyrfel\Helper\Callback', array('__invoke'), array(), '', false); | |
$object->expects($this->any()) | |
->method('__invoke') | |
->with('a', 'd') | |
->will($this->returnValue(self::RETURN_VALUE)); | |
$callback = new Callback($object, '__invoke', 'c', 'd'); | |
$this->assertSame($callback, $callback->overrideInstantiationArguments()); | |
$this->assertSame(self::RETURN_VALUE, $callback('a')); | |
} | |
/** | |
* tests that it works without invocation arguments | |
*/ | |
public function testEmptyInvocationArgs() | |
{ | |
$object = $this->getMock('Wyrfel\Helper\Callback', array('__invoke'), array(), '', false); | |
$object->expects($this->any()) | |
->method('__invoke') | |
->with('c', 'd') | |
->will($this->returnValue(self::RETURN_VALUE)); | |
$callback = new Callback($object, '__invoke', 'c', 'd'); | |
$this->assertSame(self::RETURN_VALUE, $callback()); | |
} | |
/** | |
* tests that it works without instantiation arguments | |
*/ | |
public function testEmptyInstantiationArgs() | |
{ | |
$object = $this->getMock('Wyrfel\Helper\Callback', array('__invoke'), array(), '', false); | |
$object->expects($this->any()) | |
->method('__invoke') | |
->with('a', 'b') | |
->will($this->returnValue(self::RETURN_VALUE)); | |
$callback = new Callback($object, '__invoke'); | |
$this->assertSame(self::RETURN_VALUE, $callback('a', 'b')); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment