It will introduce new complexities in debugging and error handling and also existing library implementations (e.g., Laravel's pipeline) already offer similar functionality without needing language changes. Instead of achieving the same result with simple code why do we attempt to pollute the current syntax.
$value = 'Hello world';
array_map(static function($fn) use (&$value){
if(is_callable($fn)){
$value = $fn($value);
}
}, [
'htmlentities',
'str_split',
fn($x) => array_map('strtoupper', $x),
fn($x) => array_filter($x, fn($v) => $v != 'O')
]);
var_dump($value);
Comparing to the code below, it is not usable and clear. the only benefit of that can be just knowing the name of the variable. other than that the syntax is way far from PHP and confusing. the value variable should be defined with type and when you start adding the parts that result will be like the __set
method
class User
{
public string $name;
public function __construct(string $name) {
$this->name = $name;
}
public function __set(string $name, string $value){
if($name !== 'name'){
return;
}
if (strlen($value) === 0) {
throw new ValueError("Name must be non-empty");
}
$field = ucfirst($value);
}
}
$u = new User('');
var_dump($u->name);`
I think, it is not correct way of a clean code attempt, removing parentheses will reduce code readability and clarity, especially for those new to PHP or maintaining others' code, it also will introduce inconsistencies in code bases where some use parentheses and others do not. It might increase the risk of subtle bugs, particularly in complex expressions or when refactoring code.
(new Highlighter())->withGutter();
is much more clear to separate visually
I don't think removing parenthese is a good idea
There are some arguments against the implementation and I agree to those. But in addition I don't agree to the concept itself, personally, because I am convinced that immutability is key when enforcing domain logic. E.g. the example above could be replaced by:
readonly class User { public function __construct(public string $name) { if (strlen($name) === 0) { throw new ValueError('Name must be non-empty'); } } public function withName(string $newName): self { return new self($newName); } }
Or, even better IMO, with value objects that validate themselves:
readonly class User { public function __construct(public Name $name) {} public function withName(Name $newName): self { return new self($newName); } } readonly class Name { public function __construct(public string $value) { if (strlen($value) === 0) { throw new ValueError('Name must be non-empty'); } } }
Granted, this is only one example and immutabilty is not a silver-bullet. But I haven't come across a usecase for property hooks that was really convincing yet
Moving to C# is not a good way IMHO. We will end with classes where properties are heavily mixed with the logic before actually we see class methods.
While I'm not against the concept in general, this implementation is not well-done. The $value variables comes from nowhere and makes it confusing - it looks like an undefined variable and a quick glance at it, was the first thing I thought - where is $value coming from? Why not just use $name within that block? Same with $field? Why not just return the value that is going to be set? This is one of the more confusing RFCs I've seen and does not follow the PHP-code style, makes things confusing for both new and experienced coders. In it's current format, I can't approve with good conscience.
Still hard to read. No extra benefits.
The only clean solution is to use scalar types (string, int, float, boolean) and arrays like objects:
$result = "Hello World"->htmlentities()->split()->map(strtoupper(...))->filter(fn($v) => $v != 'O');
Chain, clean oop, readable, IDE hint, no value parameter, no prefixes and an opportunity to correct the functions inconsistency. It could works beside functions: strtoupper($name)
and $name->toUpper()
.
I see no immediate benefit of the proposed solution over the userland implementations. The RFC mentions a shopping cart example, but I don't think that's cleaner than using league/pipeline or Laravel's pipeline.
It's a bit messy for the simpler examples as well.
It's almost as messy as putting all the functions into each other.