$payload * @param list $volatileFields * @return array */ public function normalize(array $payload, array $volatileFields = []): array { $volatileLookup = array_fill_keys(array_map('strval', $volatileFields), true); return $this->normalizeValue($payload, $volatileLookup); } /** * @param array $normalizedPayload */ public function payloadHash(array $normalizedPayload): string { return hash('sha256', $this->canonicalJson($normalizedPayload)); } /** * @param array $payload */ public function canonicalJson(array $payload): string { return json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); } /** * @param array $volatileLookup * @return mixed */ private function normalizeValue(mixed $value, array $volatileLookup): mixed { if (! is_array($value)) { return $value; } if ($this->isList($value)) { return array_map(fn (mixed $item): mixed => $this->normalizeValue($item, $volatileLookup), $value); } $normalized = []; foreach ($value as $key => $nestedValue) { $key = (string) $key; if (isset($volatileLookup[$key])) { continue; } $normalized[$key] = $this->normalizeValue($nestedValue, $volatileLookup); } ksort($normalized); return $normalized; } private function isList(array $value): bool { return array_is_list($value); } }