$raw */ public function __construct( public readonly string $cep = '', public readonly string $logradouro = '', public readonly string $complemento = '', public readonly string $unidade = '', public readonly string $bairro = '', public readonly string $localidade = '', public readonly string $uf = '', public readonly string $estado = '', public readonly string $regiao = '', public readonly string $ibge = '', public readonly string $gia = '', public readonly string $ddd = '', public readonly string $siafi = '', public readonly ?Geo $geo = null, public readonly array $raw = [], ) { } /** * Build from the decoded response. * * Unknown fields are ignored during construction but preserved in * {@see Address::$raw}. A new field in the API therefore cannot break this * library. * * @param array $data */ public static function fromArray(array $data): self { $values = []; foreach (self::FIELDS as $name) { $value = $data[$name] ?? ''; $values[$name] = is_scalar($value) ? (string) $value : ''; } return new self( cep: $values['cep'], logradouro: $values['logradouro'], complemento: $values['complemento'], unidade: $values['unidade'], bairro: $values['bairro'], localidade: $values['localidade'], uf: $values['uf'], estado: $values['estado'], regiao: $values['regiao'], ibge: $values['ibge'], gia: $values['gia'], ddd: $values['ddd'], siafi: $values['siafi'], geo: Geo::fromArray($data['geo'] ?? null), raw: $data, ); } /** * Read any field of the raw response, including one the API grew after * this release, or `null` when it is absent. */ public function field(string $name): ?string { $value = $this->raw[$name] ?? null; return is_scalar($value) ? (string) $value : null; } /** * The CEP with its mask: `01001-000`. * * The API always returns it unmasked; formatting is presentation, and it * lives here so it does not become a repeated `sprintf` in every project * that uses this. */ public function formattedCep(): string { return substr($this->cep, 0, 5) . '-' . substr($this->cep, 5, 3); } /** * @return array */ public function toArray(): array { $out = []; foreach (self::FIELDS as $name) { $out[$name] = $this->{$name}; } $out['geo'] = $this->geo?->toArray(); return $out; } }