> > https://hive.blog/php/@crell/improving-php-s-object-ergonomics


Thanks Larry, that's a good way to move forward on these topics.

I generally like the ideal of combining property declaration and
> constructors. I've had this on my mind for a while already, and also
> received the same suggestion from a couple of other people (I think Nicolas
> was one of them?)


I confirm: that'd be super useful to clean the boilerplate.


> large enough that I will often go with a quick and simple ad-hoc array
> structure rather than declaring an explicit value object type.


Yes


> The main concern, as others have already mentioned, is that these inline
> declarations can end up being quite verbose, especially once attributes get
> involved.
>

I don't share this concern with attributes: they mix without any ambiguity,
which is what matters.
No syntax is perfect, ppl that prefer the current way will still be able to
use it.



> Named parameters are a pretty tough topic. I think one of the main points
> of contention is that they make the parameters names part of the API
> contract, and as such also subject to LSP. Your proposal offers two
> possible ways to side-step this: First, by making named parameters opt-in
> with a special syntax {}. Second, by limiting them to constructors. The
> latter variant still exposes parameter names in the API, but at least does
> not require their preservation across inheritance, as constructors are
> excluded from LSP. I'm somewhat torn on this, because it makes named
> parameters unusable with the very large body of existing methods, and
> introduces an inconsistency in which methods can use named params and which
> don't.
>

I'd like to propose something on the topic.
I'm adding object literals to the mix because that's another feature of the
language that we're missing a lot IMHO.
Actually, there is one existing syntax for objects: (object) [...]

My proposal is to allow any class in the casting operator: (Foo) [...]
By default, all keys of the casted array would map to properties (with an
error when no matching property exists in the current visibility scope). We
would then allow for a new constructor method, either:
public function __create(array $values)
or:
public static function __create(array $values): static

This method would take over the cast operator and decide how to construct
an instance of such a class.

There is one drawback: accepted keys are not documented. Sure, property
declarations can give a big hint.

But I think we can solve this issue later: it's not a blocker to still make
things work nicely. Also, this issue already exists with all methods that
accept an array of options - and we'll find a solution for those - either
using docblocks (there are already ways to use them for that) or using
attributes (would be the best of course, once we have them.)

Note that this __create() method looks a lot like __unserialize(): it's
just called at a different place, but the implementations could be
essentially the same.

Regarding the remainder, I think that all of readonly properties,
> asymmetric visibility and property accessors have their place and value,
> with some overlap between them. As you already mentioned, the previous
> property accessors proposal also included asymettric visibility as a
> special case, and that's how I would introduce it as well.
>

Máté suggested this syntax and it has my preference over the one you menton
Larry: doubling the visibility keyword could be enough to express
read+write access:

public private $property; <= public read access, private write access


However, I generally think that the main value really is the readonly
> properties as proposed in the recent RFC. Nowadays, a large fraction of the
> classes I use are immutable value objects, for which public readonly
> properties provide a much closer match to the semantics I want.
>
> I think that the problem with with-er methods is just that: It's a problem
> with with-er methods. It's what happens when you try to shove immutability
> into something that is not actually being used in an immutable manner.
> Don't pretend things are immutable when they aren't...
>

I think "withers" solve the problem of immutability in a very pragmatic and
convenient way.

Take e.g. "private": it can be bypassed using closure rebinding or
reflection, and this is really useful, e.g. to build "friendship" relations
between classes in the same package (like in C++).

On the other side, "final" is a real pain when needing to write
proxies/decorators. It just blocks extensibility for no technical reasons
really. Let me explain: If as a consumer, I DO want to extend a class,
nothing will prevent me to do so. There is always the last resort solution,
which is patching the too restrictive source class, either using a fork or
some code rewriting tool.

Either way, what matters is who is in charge of dealing with the issues
this might create. In both ways, what matters is that the original author
won't be bothered for things that are not its responsibility. "I broke your
app because you messed up with that private property on a class I
authored?" no my problem. About final, I usually prefer using the "@final"
annotation: it expressed exactly what I need to express as the author of
the code: "if you extend, you're on your own - but I'm not dictating what
you can/can't do either".

I think this reasoning applies to my view on immutability :)

Cheers,
Nicolas

Reply via email to