public function getMock() { $mock = $this->testCase->getMock('stdClass', $this->functions, array(), 'PHPUnit_Extension_FunctionMocker_' . uniqid()); foreach ($this->functions as $function) { $fqFunction = $this->namespace . '\\' . $function; if (in_array($fqFunction, static::$mockedFunctions, true)) { continue; } if (!extension_loaded('runkit') || !ini_get('runkit.internal_override')) { PHPUnit_Extension_FunctionMocker_CodeGenerator::defineFunction($function, $this->namespace); } elseif (!function_exists('__phpunit_function_mocker_' . $function)) { runkit_function_rename($function, '__phpunit_function_mocker_' . $function); error_log($function); runkit_method_redefine($function, function () use($function) { if (!isset($GLOBALS['__PHPUNIT_EXTENSION_FUNCTIONMOCKER'][$this->namespace])) { return call_user_func_array('__phpunit_function_mocker_' . $function, func_get_args()); } return call_user_func_array(array($GLOBALS['__PHPUNIT_EXTENSION_FUNCTIONMOCKER'][$this->namespace], $function), func_get_args()); }); var_dump(strlen("foo")); } static::$mockedFunctions[] = $fqFunction; } if (!isset($GLOBALS['__PHPUNIT_EXTENSION_FUNCTIONMOCKER'])) { $GLOBALS['__PHPUNIT_EXTENSION_FUNCTIONMOCKER'] = array(); } $GLOBALS['__PHPUNIT_EXTENSION_FUNCTIONMOCKER'][$this->namespace] = $mock; return $mock; }
/** * Creates runkit method to be used for mocking, taking care of callback to this object. * * Also temporary renames the original method if there is. */ protected function createFunction() { list($class, $method) = $this->getClassAndMethod(); $this->restore_name = 'restore_' . $class . '_' . $method . '_' . $this->id . '_' . uniqid(); // We save the original method in the class for restoring. runkit_method_copy($class, $this->restore_name, $class, $method); runkit_method_redefine($class, $method, '', $this->getCallback(), RUNKIT_ACC_STATIC); $this->active = true; }
public static function reload_method($classname, $methodname) { $method = new ReflectionMethod($classname, $methodname); $visibility = RUNKIT_ACC_PUBLIC; if ($method->isProtected()) { $visibility = RUNKIT_ACC_PROTECTED; } else { if ($method->isPrivate()) { $visibility = RUNKIT_ACC_PRIVATE; } } if ($method->isStatic()) { $visibility = $visibility | RUNKIT_ACC_STATIC; } return runkit_method_redefine($classname, $methodname, self::getMethodArguments($classname, $methodname), self::getMethodCode($classname, $methodname), $visibility); }
/** * Constructs a new callable object, abstracting * differences between the different constructs * PHP supports. * * \param mixed $callable * A callable item. It must be compatible * with the PHP callback pseudo-type. * * \throw InvalidArgumentException * The given item is not compatible * with the PHP callback pseudo-type. * * \see * More information on the callback pseudo-type can be found here: * http://php.net/language.pseudo-types.php#language.types.callback */ public function __construct($callable) { if (!is_callable($callable, false, $representation)) { throw new \InvalidArgumentException('Not a valid callable'); } if (!self::$patched) { self::$patched = true; // @codeCoverageIgnoreStart // Adds support for references to invoke() on PHP 5.6.0+. if (version_compare(PHP_VERSION, '5.6.0', '>=') && function_exists('runkit_method_redefine')) { runkit_method_redefine(__CLASS__, '__invoke', '&...$args', 'return call_user_func_array($this->callableObj, $args);'); } // @codeCoverageIgnoreEnd } // This happens for anonymous functions // created with create_function(). if (is_string($callable) && $representation == "") { $representation = $callable; } $this->callableObj = $callable; $this->representation = $representation; }
/** * @param \Runkit\RunkitMethod $method * * @return boolean */ public function redefineMethod(\Runkit\RunkitMethod $method) { if (!function_exists('runkit_method_redefine')) { return false; } return runkit_method_redefine($method->getClass(), $method->getName(), (string) $method->getArguments(), $method->getCode()->get(), $method->getAccess()); }
protected function _reverseMethodCallRedirection() { $newOrigFuncName = $this->_functionName . $this->_origFuncSuffix; $spyFuncName = $this->_functionName . $this->_spyFuncSuffix; $isStatic = (new \ReflectionMethod($this->_context, $this->_functionName))->isStatic(); if ($isStatic) { $origCallback = 'array("' . $this->_context . '", "' . $newOrigFuncName . '")'; } else { $origCallback = 'array($this, "' . $newOrigFuncName . '")'; } runkit_method_remove($this->_context, $spyFuncName); //keep memory address of function to prevent seg fault runkit_method_redefine($this->_context, $this->_functionName, '', '$args = func_get_args(); return call_user_func_array(' . $origCallback . ', $args);', RUNKIT_ACC_PUBLIC | ($isStatic ? RUNKIT_ACC_STATIC : 0)); }
/** * Mock a method. * * Replace the code of a function of a specific class * * @param Callable $method Method defined in an array form * @param String $mock Replacement code for the method * @param String $visibility Visibility of the redefined method * @param String $args Comma-delimited list of arguments for the redefined method * * @return void */ protected function mock_method($method, $mock, $visibility = 'public', $args = '') { $class_name = is_object($method[0]) ? get_class($method[0]) : $method[0]; $method_name = $method[1]; if (method_exists($class_name, $method_name . self::FUNCTION_ID) === FALSE) { runkit_method_copy($class_name, $method_name . self::FUNCTION_ID, $class_name, $method_name); } switch ($visibility) { case 'public': $visibility_flag = RUNKIT_ACC_PUBLIC; break; case 'protected': $visibility_flag = RUNKIT_ACC_PROTECTED; break; case 'private': $visibility_flag = RUNKIT_ACC_PRIVATE; break; } runkit_method_redefine($class_name, $method_name, $args, $mock, $visibility_flag); }
/** * @Given class :fqcn has method :method with arguments :args and code */ public function classHasMethodWithArgumentsAndCode($fqcn, $method, $args, PyStringNode $code) { $this->checkRunkit(); $class = new \ReflectionClass($fqcn); if (!$class->hasMethod($method)) { throw new \RuntimeException(sprintf('Class %s does not have method %s', $fqcn, $method)); } runkit_method_redefine($fqcn, $method, $args, $code->__toString(), RUNKIT_ACC_PUBLIC); }