$normalizedPayload * @return array */ public function build( string $resourceType, string $sourceSurface, string $commandContractName, string $commandContractVersion, string $payloadShapeVersion, string $normalizerVersion, array $normalizedPayload, ): array { return $this->canonicalize([ 'resource_type' => $resourceType, 'source_surface' => $sourceSurface, 'command_contract_name' => $commandContractName, 'command_contract_version' => $commandContractVersion, 'payload_shape_version' => $payloadShapeVersion, 'normalizer_version' => $normalizerVersion, 'normalized_payload' => $normalizedPayload, ]); } /** * @param array $hashInput */ public function hash(array $hashInput): string { return hash('sha256', $this->canonicalJson($hashInput)); } /** * @param array $hashInput */ public function canonicalJson(array $hashInput): string { return json_encode($this->canonicalize($hashInput), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); } private function canonicalize(mixed $value): mixed { if (! is_array($value)) { return $value; } if (array_is_list($value)) { return array_map(fn (mixed $item): mixed => $this->canonicalize($item), $value); } $normalized = []; foreach ($value as $key => $nestedValue) { if ($nestedValue === null) { continue; } $normalized[(string) $key] = $this->canonicalize($nestedValue); } ksort($normalized, SORT_NATURAL | SORT_FLAG_CASE); return $normalized; } }