public function runHooks($method, $arguments, $type = 'method')
{
$result = array('return' => null, 'numHooksRun' => 0, 'methodExists' => false, 'replace' => false);
$realMethod = "___{$method}";
if ($type == 'method') {
$result['methodExists'] = method_exists($this, $realMethod);
}
if (!$result['methodExists'] && !self::isHooked($method . ($type == 'method' ? '()' : ''))) {
return $result;
// exit quickly when we can
}
$hooks = $this->getHooks($method);
foreach (array('before', 'after') as $when) {
if ($type === 'method' && $when === 'after' && $result['replace'] !== true) {
if ($result['methodExists']) {
$result['return'] = call_user_func_array(array($this, $realMethod), $arguments);
} else {
$result['return'] = null;
}
}
foreach ($hooks as $priority => $hook) {
if (!$hook['options'][$when]) {
continue;
}
if (!empty($hook['options']['objMatch'])) {
$objMatch = $hook['options']['objMatch'];
// object match comparison to determine at runtime whether to execute the hook
if (is_object($objMatch)) {
if (!$objMatch->matches($this)) {
continue;
}
} else {
if ((string) $this != $objMatch) {
continue;
}
}
}
if ($type == 'method' && !empty($hook['options']['argMatch'])) {
// argument comparison to determine at runtime whether to execute the hook
$argMatches = $hook['options']['argMatch'];
$matches = true;
foreach ($argMatches as $argKey => $argMatch) {
$argVal = isset($arguments[$argKey]) ? $arguments[$argKey] : null;
if (is_object($argMatch)) {
// Selectors object
if (is_object($argVal)) {
$matches = $argMatch->matches($argVal);
} else {
// we don't work with non-object here
$matches = false;
}
} else {
if (is_array($argVal)) {
// match any array element
$matches = in_array($argMatch, $argVal);
} else {
// exact string match
$matches = $argMatch == $argVal;
}
}
if (!$matches) {
break;
}
}
if (!$matches) {
continue;
}
// don't run hook
}
$event = new HookEvent();
$event->object = $this;
$event->method = $method;
$event->arguments = $arguments;
$event->when = $when;
$event->return = $result['return'];
$event->id = $hook['id'];
$event->options = $hook['options'];
$toObject = $hook['toObject'];
$toMethod = $hook['toMethod'];
if (is_null($toObject)) {
$toMethod($event);
} else {
$toObject->{$toMethod}($event);
}
$result['numHooksRun']++;
if ($when == 'before') {
$arguments = $event->arguments;
$result['replace'] = $event->replace === true || $result['replace'] === true;
if ($result['replace']) {
$result['return'] = $event->return;
}
}
if ($when == 'after') {
$result['return'] = $event->return;
}
}
}
return $result;
}