$cb ) { if ( $cb['priorities'] !== $cbs_b[ $key ]['priorities'] ) { $moved[] = $cb + array( 'to' => $cbs_b[ $key ]['priorities'] ); } } $assets_a = self::assets( $a ); $assets_b = self::assets( $b ); $totals = array(); foreach ( array( 'hooks', 'callbacks', 'queries', 'errors' ) as $key ) { $totals[ $key ] = array( 'a' => isset( $a['summary'][ $key ] ) ? (int) $a['summary'][ $key ] : 0, 'b' => isset( $b['summary'][ $key ] ) ? (int) $b['summary'][ $key ] : 0, ); } return array( 'hooksOnlyA' => array_values( array_diff( $hooks_a, $hooks_b ) ), 'hooksOnlyB' => array_values( array_diff( $hooks_b, $hooks_a ) ), 'cbAdded' => array_values( array_diff_key( $cbs_b, $cbs_a ) ), 'cbRemoved' => array_values( array_diff_key( $cbs_a, $cbs_b ) ), 'cbMoved' => $moved, 'assetsAdded' => array_values( array_diff( $assets_b, $assets_a ) ), 'assetsRemoved' => array_values( array_diff( $assets_a, $assets_b ) ), 'totals' => $totals, ); } /** * Whether a comparison found any structural difference. * * @param array $diff From compare(). * @return bool */ public static function has_changes( array $diff ) { foreach ( array( 'hooksOnlyA', 'hooksOnlyB', 'cbAdded', 'cbRemoved', 'cbMoved', 'assetsAdded', 'assetsRemoved' ) as $key ) { if ( ! empty( $diff[ $key ] ) ) { return true; } } return false; } private static function hook_names( $map ) { $names = array(); foreach ( $map['hooks'] as $hook ) { if ( empty( $hook['z'] ) ) { $names[] = (string) $hook['n']; } } return $names; } /** * Callbacks keyed by hook, callback and owner, with their priorities. */ private static function callbacks( $map ) { $components = isset( $map['components'] ) && is_array( $map['components'] ) ? $map['components'] : array(); $out = array(); foreach ( $map['hooks'] as $hook ) { if ( ! empty( $hook['z'] ) || empty( $hook['cb'] ) ) { continue; } foreach ( $hook['cb'] as $cb ) { // Closures have no stable name, so they are identified by file. $label = 'Closure' === $cb['l'] ? 'Closure@' . $cb['f'] : $cb['l']; $key = $hook['n'] . '|' . $label . '|' . $cb['c']; if ( ! isset( $out[ $key ] ) ) { $out[ $key ] = array( 'hook' => (string) $hook['n'], 'callback' => (string) $label, 'component' => isset( $components[ $cb['c'] ]['name'] ) ? (string) $components[ $cb['c'] ]['name'] : (string) $cb['c'], 'priorities' => array(), ); } $out[ $key ]['priorities'][] = (int) $cb['p']; } } foreach ( $out as $key => $cb ) { sort( $out[ $key ]['priorities'] ); } return $out; } private static function assets( $map ) { $out = array(); if ( empty( $map['assets'] ) || ! is_array( $map['assets'] ) ) { return $out; } foreach ( array( 'scripts', 'styles' ) as $type ) { if ( empty( $map['assets'][ $type ] ) ) { continue; } foreach ( $map['assets'][ $type ] as $asset ) { $out[] = $type . ':' . $asset['h']; } } return $out; } /** * Plain-text report for the command line. * * @param array $diff From compare(). * @return string */ public static function to_text( array $diff ) { $lines = array(); $sections = array( 'hooksOnlyA' => 'Hooks only in A', 'hooksOnlyB' => 'Hooks only in B', 'assetsAdded' => 'Assets added in B', 'assetsRemoved' => 'Assets missing in B', ); foreach ( $sections as $key => $title ) { if ( $diff[ $key ] ) { $lines[] = $title . ':'; foreach ( $diff[ $key ] as $item ) { $lines[] = ' ' . $item; } } } $cb_sections = array( 'cbAdded' => 'Callbacks added in B', 'cbRemoved' => 'Callbacks missing in B', 'cbMoved' => 'Callbacks with a different priority', ); foreach ( $cb_sections as $key => $title ) { if ( $diff[ $key ] ) { $lines[] = $title . ':'; foreach ( $diff[ $key ] as $cb ) { $line = sprintf( ' %s %s (%s, priority %s', $cb['hook'], $cb['callback'], $cb['component'], implode( ',', $cb['priorities'] ) ); if ( isset( $cb['to'] ) ) { $line .= ' -> ' . implode( ',', $cb['to'] ); } $lines[] = $line . ')'; } } } $lines[] = 'Totals (A -> B):'; foreach ( $diff['totals'] as $key => $pair ) { $lines[] = sprintf( ' %-10s %d -> %d', $key, $pair['a'], $pair['b'] ); } return implode( "\n", $lines ); } }