06.09.2016 9:13 PM "Fleshgrinder" <p...@fleshgrinder.com> napisał(a): > > I understand the concerns of all of you very well and it's nice to see a > discussion around this topic. Fun fact, we are not the only ones with > these issues: https://github.com/dotnet/roslyn/issues/159 > > On 9/6/2016 6:01 PM, Larry Garfield wrote: > > How big of a need is it to allow returning $this instead of $clone, > > and/or can that be internalized somehow as well? With copy-on-write, > > is that really an issue beyond a micro-optimization? > > I asked the same question before because I am also unable to answer this > question regarding the engine. > > However, for me it is more than micro-optimization, it is about identity. > > final class Immutable { > // ... the usual ... > public function withValue($value) { > $clone = clone $this; > $clone->value = $value; > return $clone; > } > } > > $red = new Immutable('red'); > $still_red = $red->withValue('red'); > > var_dump($red === $still_red); // bool(false) > > This is a problem in terms of value objects and PHP still does not allow > us operator overloading. A circumstance that I definitely want to > address in the near future. > > But the keyword copy-on-write leads me to yet another proposal, actually > your input led me to two new proposals. > > # Copy-on-Write (CoW) > Why are we even bothering on finding ways on making it hard for > developers while the solution to our problem is directly in front of us: > PHP Strings! >
AFAIK CoW in case of objects would be impossible to implement. > Every place in a PHP program refers to the same string if that string is > the same string. In the second someone mutates that string in any way > she gets her own mutated reference to that string. > > That's exactly how we could deal with immutable objects. Developers do > not need to take care of anything, they just write totally normal > objects and the engine takes care of everything. > > This approach also has the advantage that the return value of any method > is (as always) up to the developers. > > (Cloning is disabled and results in an error as is because it makes no > sense at all.) > > # Identity > This directly leads to the second part of my thoughts and I already > touched that topic: identity. If we have two strings their binary > representation is always the same: > > var_dump('string' === 'string'); // bool(true) > > This is the exact behavior one wants for value objects too. Hence, > immutable objects should have this behavior since they identify > themselves by their values and not through instances. If I create two > instances of Money with the amount 10 and the Currency EUR then they are > always the same, no matter what. This would also mean that no developer > ever needs to check if the new value is the same as the existing one, > nor does anyone ever has to implement the flyweight pattern for > immutable objects. > > A last very important attribute is that it does not matter in which > thread an immutable value object is created because it always has the > same identity regardless of it. > > This could easily be achieved by overwriting the object hashes > (spl_object_hash) with something that hashes based on the values, and > predictably across threads (UUIDs?). > > # Full Example > <?php > > final immutable class ValueObject { > > public $value; > > public function __construct($value) { > $this->value = $value; > } > > public function withValue($value) { > $this->value = $value; > } > > } > > class A { > > public $vo; > > public function __construct(ValueObject $vo) { > $this->vo = $vo; > } > > } > > class B { > > public $vo; > > public function __construct(ValueObject $vo) { > $this->vo = $vo; > } > > } > > $vo = new ValueObject(1); > > $a = new A($vo); > $b = new B($vo); > > var_dump($a->vo === $b->vo); // bool(true) > > $a->vo->withValue(2); > > var_dump($a->vo === $b->vo); // bool(false) > > $a->vo->withValue(1); > > var_dump($a->vo === $b->vo); // bool(true) > > // :) > > ?> > > -- > Richard "Fleshgrinder" Fussenegger >