Last active
April 1, 2016 13:48
-
-
Save andkirby/66ac35d1480b322233be0ae2ce40cafd to your computer and use it in GitHub Desktop.
This class can wrap each method in a class with custom code.(it wasn't tested with namespaces)
This file contains 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 | |
/** | |
* Usage: | |
* <?php | |
* // target class which should be wrapped | |
* class Class_For_Testing extends stdClass | |
* { | |
* public static function complexParams(stdClass $a, array &$foo = null, $bar = 'baz') | |
* { | |
* echo 'This is a test1' . PHP_EOL; | |
* } | |
* public function test1() | |
* { | |
* echo 'This is a test1' . PHP_EOL; | |
* } | |
* | |
* public function test2() | |
* { | |
* echo 'This is a test number 2!' . PHP_EOL; | |
* } | |
* } | |
* //create wrapper | |
* $wrapper = new DebugWrapper('Class_For_Testing'); | |
* $wrapper->setMethodInjectionCode('echo "wow! my code!\n";'); | |
* $wrapper->setMethodInjectionCodeEnd('echo "^^^ End!\n";'); | |
* echo $wrapper->wrap() . PHP_EOL; | |
* echo $wrapper->getCode() . PHP_EOL; | |
* $wrapper->loadClass(); | |
* // test wrapper | |
* $className = $wrapper->getWrappedClassName(); | |
* $test = new $className(); | |
* $test->test1(); | |
* $test->test2(); | |
* | |
* //output | |
* Wrapped_Class_For_Testing | |
* class Wrapped_Class_For_Testing extends Class_For_Testing { | |
* static public function complexParams(stdClass $a, array &$foo = NULL, $bar = 'baz') { | |
* echo "wow! my code!\n"; | |
* $result = parent::complexParams($a, $foo, $bar); | |
* echo "^^^ End!\n"; | |
* return $result; | |
* } | |
* | |
* | |
* public function test1() { | |
* echo "wow! my code!\n"; | |
* $result = parent::test1(); | |
* echo "^^^ End!\n"; | |
* return $result; | |
* } | |
* | |
* | |
* public function test2() { | |
* echo "wow! my code!\n"; | |
* $result = parent::test2(); | |
* echo "^^^ End!\n"; | |
* return $result; | |
* } | |
* | |
* } | |
* | |
* wow! my code! | |
* This is a test1 | |
* ^^^ End! | |
* wow! my code! | |
* This is a test number 2! | |
* ^^^ End! | |
*/ | |
/** | |
* Class DebugWrapper | |
*/ | |
class DebugWrapper | |
{ | |
/** | |
* Generated code | |
* | |
* @var string | |
*/ | |
protected $code = ''; | |
/** | |
* Target class name | |
* | |
* @var string | |
*/ | |
protected $className; | |
/** | |
* Code which will be added to each method | |
* | |
* @var string | |
*/ | |
protected $methodInjectionCode = "file_put_contents('/tmp/wrapping.log', __CLASS__.\"::\".__FUNCTION__, FILE_APPEND);"; | |
/** | |
* Code which will be added to each method | |
* | |
* @var string | |
*/ | |
protected $methodInjectionCodeEnd = ''; | |
/** | |
* Set class name | |
* | |
* @param $class | |
*/ | |
public function __construct($class) | |
{ | |
$this->className = $class; | |
} | |
/** | |
* Wrap class | |
* | |
* @return bool|string | |
*/ | |
public function wrap() | |
{ | |
if (!$this->isClassExists()) { | |
return false; | |
} | |
$this->writeOpenClass(); | |
//methods | |
$reflect = new ReflectionClass($this->className); | |
foreach ($reflect->getMethods() as $method) { | |
if ($method->isPrivate() || $method->isFinal()) { | |
//ignore private and final methods which cannot be inherited | |
continue; | |
} | |
list($params, $arguments) = $this->getParamsCode($method); | |
$this->writeMethod( | |
$method->getName(), | |
$params, | |
$arguments, | |
$method->isProtected() ? 'protected' : 'public', | |
$method->isStatic() | |
); | |
} | |
$this->writeCloseClass(); | |
return $this->getWrappedClassName(); | |
} | |
protected function isClassExists() | |
{ | |
return class_exists($this->className); | |
} | |
/** | |
* @return $this | |
*/ | |
protected function writeOpenClass() | |
{ | |
$this->code = ''; | |
$this->code .= "class Wrapped_{$this->className} extends {$this->className} {"; | |
return $this; | |
} | |
/** | |
* @param $method | |
* @return array | |
*/ | |
protected function getParamsCode(ReflectionMethod $method) | |
{ | |
$params = ''; | |
$arguments = ''; | |
/** @var $parameter ReflectionParameter */ | |
foreach ($method->getParameters() as $num => $parameter) { | |
if (0 === strpos($parameter->getName(), '__')) { | |
//ignore magic methods | |
continue; | |
} | |
if (0 !== $num) { | |
$params .= ', '; | |
$arguments .= ', '; | |
} | |
$params .= $this->getParameterType($parameter) . ' '; | |
if ($parameter->isPassedByReference()) { | |
$params .= '&'; | |
} | |
$params .= '$' . $parameter->getName(); | |
$arguments .= '$' . $parameter->getName(); | |
if ($parameter->isDefaultValueAvailable()) { | |
$params .= ' = '; | |
if ($parameter->isDefaultValueConstant()) { | |
$params .= $parameter->getDefaultValueConstantName(); | |
} else { | |
$params .= var_export($parameter->getDefaultValue(), true); | |
} | |
} | |
} | |
return array($params, $arguments); | |
} | |
/** | |
* @param $name | |
* @param $params | |
* @param $arguments | |
* @param $visibility | |
* @param $static | |
* @return $this | |
*/ | |
protected function writeMethod($name, $params, $arguments, $visibility, $static) | |
{ | |
$this->code .= "\n"; | |
$static = $static ? 'static ' : ''; | |
$this->code .= " {$static}{$visibility} function $name($params) {\n"; | |
$this->code .= ' ' . $this->getMethodInjectionCode() . "\n"; | |
$this->code .= " \$result = parent::$name($arguments);\n"; | |
$this->code .= ' ' . $this->getMethodInjectionCodeEnd() . "\n"; | |
$this->code .= " return \$result;\n"; | |
$this->code .= " }\n"; | |
$this->code .= "\n"; | |
return $this; | |
} | |
/** | |
* @return $this | |
*/ | |
protected function writeCloseClass() | |
{ | |
$this->code .= "}\n"; | |
return $this; | |
} | |
public function getWrappedClassName() | |
{ | |
return 'Wrapped_' . $this->className; | |
} | |
/** | |
* Get parameter type | |
* | |
* @param ReflectionParameter $parameter | |
* @return string|null | |
*/ | |
protected function getParameterType(ReflectionParameter $parameter) | |
{ | |
$export = ReflectionParameter::export( | |
array( | |
$parameter->getDeclaringClass()->name, | |
$parameter->getDeclaringFunction()->name, | |
), | |
$parameter->name, | |
true | |
); | |
return preg_match('/[>] ([A-z]+) /', $export, $matches) | |
? $matches[1] : null; | |
} | |
/** | |
* @return string | |
*/ | |
public function getMethodInjectionCode() | |
{ | |
return $this->methodInjectionCode; | |
} | |
/** | |
* @param string $methodInjectionCode | |
* @return DebugWrapper | |
*/ | |
public function setMethodInjectionCode($methodInjectionCode) | |
{ | |
$this->methodInjectionCode = $methodInjectionCode; | |
return $this; | |
} | |
/** | |
* @return string | |
*/ | |
public function getMethodInjectionCodeEnd() | |
{ | |
return $this->methodInjectionCodeEnd; | |
} | |
/** | |
* @param string $methodInjectionCodeEnd | |
* @return DebugWrapper | |
*/ | |
public function setMethodInjectionCodeEnd($methodInjectionCodeEnd) | |
{ | |
$this->methodInjectionCodeEnd = $methodInjectionCodeEnd; | |
return $this; | |
} | |
/** | |
* @return string|null | |
*/ | |
public function getCode() | |
{ | |
return $this->code; | |
} | |
/** | |
* @return $this | |
*/ | |
public function loadClass() | |
{ | |
eval($this->code); | |
return $this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment