function call($func, $args = NULL, $hooks = '')
{
if (!is_array($args)) {
$args = [$args];
}
// Grab the real handler behind the string representation
if (is_string($func)) {
$func = $this->grab($func, $args);
}
// Execute function; abort if callback/hook returns FALSE
if (!is_callable($func)) {
// No route handler
if ($hooks == 'beforeroute,afterroute') {
$allowed = [];
if (is_array($func)) {
$allowed = array_intersect(array_map('strtoupper', get_class_methods($func[0])), explode('|', self::VERBS));
}
header('Allow: ' . implode(',', $allowed));
$this->error(405);
} else {
user_error(sprintf(self::E_Method, is_string($func) ? $func : $this->stringify($func)), E_USER_ERROR);
}
}
$obj = FALSE;
if (is_array($func)) {
$hooks = $this->split($hooks);
$obj = TRUE;
}
// Execute pre-route hook if any
if ($obj && $hooks && in_array($hook = 'beforeroute', $hooks) && method_exists($func[0], $hook) && call_user_func_array([$func[0], $hook], $args) === FALSE) {
return FALSE;
}
// Execute callback
$out = call_user_func_array($func, $args ?: []);
if ($out === FALSE) {
return FALSE;
}
// Execute post-route hook if any
if ($obj && $hooks && in_array($hook = 'afterroute', $hooks) && method_exists($func[0], $hook) && call_user_func_array([$func[0], $hook], $args) === FALSE) {
return FALSE;
}
return $out;
}