+ /**
+ * @param string $event Event name
+ * @param array|callable $hook
+ * @param array $args Array of parameters passed to hook functions
+ * @param string|null $deprecatedVersion [optional]
+ * @param string &$fname [optional] Readable name of hook [returned]
+ * @return null|string|bool
+ */
+ private static function callHook( $event, $hook, array $args, $deprecatedVersion = null,
+ &$fname = null
+ ) {
+ // Turn non-array values into an array. (Can't use casting because of objects.)
+ if ( !is_array( $hook ) ) {
+ $hook = [ $hook ];
+ }
+
+ if ( !array_filter( $hook ) ) {
+ // Either array is empty or it's an array filled with null/false/empty.
+ return null;
+ }
+
+ if ( is_array( $hook[0] ) ) {
+ // First element is an array, meaning the developer intended
+ // the first element to be a callback. Merge it in so that
+ // processing can be uniform.
+ $hook = array_merge( $hook[0], array_slice( $hook, 1 ) );
+ }
+
+ /**
+ * $hook can be: a function, an object, an array of $function and
+ * $data, an array of just a function, an array of object and
+ * method, or an array of object, method, and data.
+ */
+ if ( $hook[0] instanceof Closure ) {
+ $fname = "hook-$event-closure";
+ $callback = array_shift( $hook );
+ } elseif ( is_object( $hook[0] ) ) {
+ $object = array_shift( $hook );
+ $method = array_shift( $hook );
+
+ // If no method was specified, default to on$event.
+ if ( $method === null ) {
+ $method = "on$event";
+ }
+
+ $fname = get_class( $object ) . '::' . $method;
+ $callback = [ $object, $method ];
+ } elseif ( is_string( $hook[0] ) ) {
+ $fname = $callback = array_shift( $hook );
+ } else {
+ throw new MWException( 'Unknown datatype in hooks for ' . $event . "\n" );
+ }
+
+ // Run autoloader (workaround for call_user_func_array bug)
+ // and throw error if not callable.
+ if ( !is_callable( $callback ) ) {
+ throw new MWException( 'Invalid callback ' . $fname . ' in hooks for ' . $event . "\n" );
+ }
+
+ // mark hook as deprecated, if deprecation version is specified
+ if ( $deprecatedVersion !== null ) {
+ wfDeprecated( "$event hook (used in $fname)", $deprecatedVersion );
+ }
+
+ // Call the hook.
+ $hook_args = array_merge( $hook, $args );
+ return call_user_func_array( $callback, $hook_args );
+ }
+