$tickEntry the entry to insert. * @return void */ public static function interleave($registry, string $headId, array $tickEntry): void { if (!is_object($registry) || !isset($registry->callbacks) || !is_array($registry->callbacks)) { return; } foreach ($registry->callbacks as $priority => $entries) { if (!is_array($entries) || isset($entries[$headId]) || isset($entries[self::LEAD_KEY])) { continue; } $rebuilt = array(self::LEAD_KEY => $tickEntry); $n = 0; foreach ($entries as $idx => $entry) { $rebuilt[$idx] = $entry; $rebuilt[self::TICK_PREFIX . $n++] = $tickEntry; } $registry->callbacks[$priority] = $rebuilt; } } /** * Walk the registry in core's iteration order and split the real * entries into the groups that ran between consecutive ticks. Group 0 * starts after the head; the tail and (when interleaved) every * TICK_PREFIX key end a group. On an action that was not interleaved * every callback lands in group 0. Null when the head is missing. * * @param array $callbacks the registry's callbacks property. * @param string $headId * @param string $tailId * @param bool $interleaved * @return array>|null groups of callables. */ public static function groupsBetweenTicks(array $callbacks, string $headId, string $tailId, bool $interleaved): ?array { $prefixLength = strlen(self::TICK_PREFIX); $groups = array(); $current = null; foreach ($callbacks as $entries) { if (!is_array($entries)) { continue; } foreach ($entries as $idx => $entry) { if ($idx === $headId) { $current = array(); continue; } if ($current === null) { continue; } $isTick = $idx === $tailId || ($interleaved && is_string($idx) && strncmp($idx, self::TICK_PREFIX, $prefixLength) === 0); if ($isTick) { $groups[] = $current; $current = array(); continue; } $current[] = is_array($entry) && array_key_exists('function', $entry) ? $entry['function'] : $entry; } } if ($current === null) { return null; } $groups[] = $current; return $groups; } }