public function defineFunction($name, $namespace, $callback)
{
$signature = $this->signatureInspector->callbackSignature($callback);
$fullName = $namespace . '\\' . $name;
$key = strtolower($fullName);
if (isset(self::$hooks[$key])) {
if ($signature !== self::$hooks[$key]['signature']) {
throw new FunctionSignatureMismatchException($fullName);
}
$replaced = self::$hooks[$key]['callback'];
} else {
$replaced = null;
if (function_exists($fullName)) {
throw new FunctionExistsException($fullName);
}
$source = $this->hookGenerator->generateHook($name, $namespace, $signature);
$reporting = error_reporting(E_ERROR | E_COMPILE_ERROR);
$error = null;
try {
eval($source);
} catch (ParseError $e) {
$error = new FunctionHookGenerationFailedException($fullName, $callback, $source, error_get_last(), $e);
// @codeCoverageIgnoreStart
} catch (ParseException $e) {
$error = new FunctionHookGenerationFailedException($fullName, $callback, $source, error_get_last(), $e);
} catch (Throwable $error) {
// re-thrown after cleanup
} catch (Exception $error) {
// re-thrown after cleanup
}
// @codeCoverageIgnoreEnd
error_reporting($reporting);
if ($error) {
throw $error;
}
if (!function_exists($fullName)) {
// @codeCoverageIgnoreStart
throw new FunctionHookGenerationFailedException($fullName, $callback, $source, error_get_last());
// @codeCoverageIgnoreEnd
}
}
self::$hooks[$key] = array('callback' => $callback, 'signature' => $signature);
return $replaced;
}