On 02/01/2015 02:55 AM, Crypto Compress wrote:
The with*() methods in PSR-7 are documented to return a new instance,
not modify the existing instance. Yes, there's no way in PHP itself to
force that syntactically, which is why documentation exists. :-)
Also, in the benchmarks we've run the performance cost of all those new
objects is measured in nanoseconds, ie, small enough that we're not
worried about it. (Hats off to the PHP Internals folks for making that
fast!)
It is great that this is fast, but I wonder (maybe off-topic?) why do
it? I.e. it is clear that in something like:
$a = new Request->withHeaders(...)->withBody(...)
->withEncoding(...)->withETag(...)
the intermediate objects are useless and nobody needs 5 new objects when
you do it. Am I missing something here?
Hi,
my assumptions after some testing:
- This is only true in case of reassigning ($a = clone $a) the old
variable, as refcount for underlying values remains 1 for all values
in clones, so cow don't need to copy anything.
- If the old object is not thrown away, then memory consumption is
doubled and the "fast" argument is wrong.
(Performance, of cloning an object without copying values and of some
method calls, is negligible.)
I'm not sure that anyone has benchmarked the memory impact of the
immutable approach yet. I will pass that along and see what data comes out.
Omit mutator methods (with*/set*) is a simple and logical way to
achieve immutability in PHP. No need for const/final/...
(Someone feel free to declare this thread off topic now, as we're
basically just rehashing discussions had weeks ago on the FIG list.)
The original calls for immutable HTTP message objects had no with*()
methods. They objects were set from their constructor and that was the
end of it. However, many people (myself included) pointed out that such
objects, in actual practice, would be completely unusable. Middlewares
need to be able to pass information from one layer to another; the most
straightforward way to do that is (as Symfony does and PSR-7 recommends)
an attributes collection on the request. But if you can't set that
without going through a new constructor manually it becomes horribly
difficult to do. Similarly, middlewares that want to set cache
information for a whole application, encrypt/decrypt headers, or do
anything else actually useful have to manually replicate the object
themselves.
An object with a complex constructor with lots of parameters offers,
really, no value over a big-ass array. It's almost worse in my
experience. (And yes, I've used such APIs and yes, I detest them.)
Too, the constructor is obviously not part of the interface, which means
every implementation would have its own constructor, thus eliminating
the benefit of having a standard at all.
The with*() methods solved that problem entirely, and enabled a nice
fluent style for those who are into such things.
--Larry Garfield
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php