Le ven. 9 juin 2023 à 02:11, Larry Garfield <la...@garfieldtech.com> a
écrit :

> On Thu, Jun 8, 2023, at 5:39 PM, Stephen Reay wrote:
>
> > Is there a specific reason `clone with (foo: $bar);` can’t simply pass
> > the arguments given to with(), to the __clone() magic method?
> >
> > It leaves the developer free to use the passed argument(s) or deep
> > clone existing properties or a mix depending on what’s passed, and
> > seems like it has the least “magic” or unknown behaviour in terms of
> > when things happen.
> >
> > Just a thought.
>
> I experimented with that a few years back.  The results showed it is
> actually pretty awful in practice.
>
> https://peakd.com/hive-168588/@crell/object-properties-part-2-examples
>


Thanks for the link.

Instead of passing arguments to __clone(), I wondered about a new
__clone_with(array
$properties) that could be implemented next to __clone(), with the
following behavior:

   - if only __clone is implemented, same behavior as always
   - if __clone_with is implemented, __clone is never called. Instead, the
   engine calls __clone_with with the map of properties in the "with" (or
   an empty array if no "with"). In addition and *before* the call, the engine
   sets the properties according to the "with" (potentially failing
   visibility/type checks as expected)

Rewriting the example in your blog post Larry, the Request class would then
look like below.
And I think I like it.

WDYT? Mate?

class Request implements RequestInterface
{
public readonly array $headers = [];
public readonly UriInterface $uri;
public readonly string $version = '1.1';
public readonly string $method = 'GET';

public function __clone()
{
$this->uri = clone $this->uri;
}

public function __clone_with(array $properties)
{
if (isset($properties['version']) && !in_array($this->version, ['1.1', '1.0',
'2.0'])) {
throw new InvalidArgumentException($k);
}

$headers = $this->headers;

if (isset($properties['uri'])) {
$headers['host'] = $this->uri->host;
} else {
$this->uri = clone $this->uri;
}

$this->headers = $headers;
}

public function getHeader($name): string
{
return $this->headers[strtolower($name)] ?? '';
}

// Still needed because of the $preserveHost = true option.
public function withUri(UriInterface $uri, bool $preserveHost = false):
static
{
$headers = $this->headers;

// If headers were itself a pseudo-immutable object, this would be even
uglier.
if ($preserveHost && isset($headers['host'])) {
$headers['host'] = $uri->host;
}

return clone $this with (uri: $uri, headers: $headers);
}

public function withHeader(string $name, string $value): static
{
$headers = $this->headers;
$headers[strtolower($name)] = $value;

return clone $this with (headers: $headers);
}
}

Reply via email to