provider = $normalizedProvider; $this->value = $normalizedValue; } /** * Stable provider key per §4. */ public function provider(): string { return $this->provider; } /** * Provider-native identifier value per §7.3. */ public function value(): string { return $this->value; } /** * Report whether this identifier targets the supplied provider. * * Convenience guard so call sites can reject "provider 不一致" * arguments at the boundary without manually comparing * {@see self::provider()}. Comparison is strict and * case-sensitive — provider keys are lowercase ASCII per §4.2, * so case insensitivity would only mask a programming error. * * @param string $provider Provider key to test against. */ public function belongsTo( string $provider ): bool { return $this->provider === $provider; } /** * Report whether this identifier equals the supplied one. * * Equality is structural: both halves must match with strict * string equality. This is the canonical comparison for the * §7.3 uniqueness axis — `(provider, value)` taken together — * and is the only way to test identity at this layer because * PHP's `==` / `===` on objects would compare instance handles * rather than the underlying tuple. * * @param ProviderProductId $other Identifier to compare with. */ public function equals( ProviderProductId $other ): bool { return $this->provider === $other->provider && $this->value === $other->value; } /** * Render the identifier as a stable `provider:value` string. * * Used primarily by diagnostics, logs, and exception messages * where a single human-readable token is more useful than two * separate fields. The format is deliberately simple * (`amazon:B07XYZ`) and not a parser-friendly serialization * format — callers that need to round-trip through a string * should encode the two fields separately, not parse this * output. */ public function __toString(): string { return $this->provider . ':' . $this->value; } }