Hello, Internals!
As you know if you try to unpack a regular object (...$object
) you will
get an error: Only arrays and Traversables can be unpacked.
I don't really see a reason for this restriction, because foreach on
objects works perfectly fine, so I made a feature request on GitHub to
change this behavior (https://github.com/php/php-src/issues/16038) and was
advised to see opinions on this here.
So, what do you think? And does this change require RFC?
Best regards,
Ilya
Hello, Internals!
As you know if you try to unpack a regular object (
...$object
) you will
get an error: Only arrays and Traversables can be unpacked.
I don't really see a reason for this restriction, because foreach on
objects works perfectly fine, so I made a feature request on GitHub to
change this behavior (https://github.com/php/php-src/issues/16038) and
was advised to see opinions on this here.
So, what do you think? And does this change require RFC?Best regards,
Ilya
TBH, foreach on objects is already quite an abomination in itself π¬
Am 14.11.2024 um 10:59 schrieb Marco Pivetta ocramius@gmail.com:
Hello, Internals!
As you know if you try to unpack a regular object (
...$object
) you will get an error: Only arrays and Traversables can be unpacked.
I don't really see a reason for this restriction, because foreach on objects works perfectly fine, so I made a feature request on GitHub to change this behavior (https://github.com/php/php-src/issues/16038) and was advised to see opinions on this here.
So, what do you think? And does this change require RFC?TBH, foreach on objects is already quite an abomination in itself π¬
It is a bit less weird if you use value objects or json data in object form.
I would be careful to judge how other people use the language, just saying ;-)
- Chris
Am 14.11.2024 um 10:59 schrieb Marco Pivetta ocramius@gmail.com:
Hello, Internals!
As you know if you try to unpack a regular object (
...$object
) you will get an error: Only arrays and Traversables can be unpacked.
I don't really see a reason for this restriction, because foreach on objects works perfectly fine, so I made a feature request on GitHub to change this behavior (https://github.com/php/php-src/issues/16038) and was advised to see opinions on this here.
So, what do you think? And does this change require RFC?TBH, foreach on objects is already quite an abomination in itself π¬
It is a bit less weird if you use value objects or json data in object form.
I would be careful to judge how other people use the language, just saying ;-)
- Chris
Judging how one should use a language is a core component of language design.
I'm with Marco on this one, and I'd be more than happy to get rid of foreach($object), too. It's way, way more complicated a topic than you think.
How does visibility play into it?
Should hooks be invoked or no?
Do references play into anything?
Those are some of the questions we had to deal with for hooks and foreach(). It's non-trivial. You'd need to address all the same edgy issues here, too.
And that's assuming it's even a good idea, which I don't think it is. If you are using a value object to define unordered arguments, just pass the value object itself. If the receiving function can't handle that, then it is simple enough that you don't need a value object. If that's not the case, then your code design is bad and the language should not try to paper over that for you. Either simplify the function or adapt it to use a value object directly. (With union types you can even do so in a BC fashion much of the time.)
--Larry Garfield
Am 14.11.2024 um 10:59 schrieb Marco Pivetta ocramius@gmail.com:
Hello, Internals!
As you know if you try to unpack a regular object (
...$object
) you will get an error: Only arrays and Traversables can be unpacked.
I don't really see a reason for this restriction, because foreach on objects works perfectly fine, so I made a feature request on GitHub to change this behavior (https://github.com/php/php-src/issues/16038) and was advised to see opinions on this here.
So, what do you think? And does this change require RFC?TBH, foreach on objects is already quite an abomination in itself π¬
It is a bit less weird if you use value objects or json data in object form.
I would be careful to judge how other people use the language, just saying ;-)
- Chris
Judging how one should use a language is a core component of language design.
I'm with Marco on this one, and I'd be more than happy to get rid of foreach($object), too. It's way, way more complicated a topic than you think.
How does visibility play into it?
Should hooks be invoked or no?
Do references play into anything?Those are some of the questions we had to deal with for hooks and foreach(). It's non-trivial. You'd need to address all the same edgy issues here, too.
And that's assuming it's even a good idea, which I don't think it is. If you are using a value object to define unordered arguments, just pass the value object itself. If the receiving function can't handle that, then it is simple enough that you don't need a value object. If that's not the case, then your code design is bad and the language should not try to paper over that for you. Either simplify the function or adapt it to use a value object directly. (With union types you can even do so in a BC fashion much of the time.)
Agreed, this bites us constantly when needing to reason about what an "object" is in PHP.
Similar to array it mixes the concept of a struct, with that of a reference value, and "overloading" various behaviours (e.g. iterators and ArrayAccess).
It is extremely simple to go from foreach ($object as $prop) {} to forearch(get_object_vars($object) as $prop) {}
and mandating this would resolve a lot of complexity, be that from the perspective of what is "possible" or not to do, and from an engine PoV.
Best regards,
Gina P. Banyard
I do know about get_object_vars, but for me foreach ($object as $prop)
{} looks nicer and a little bit faster (probably because there are no
function calls). Also it's more flexible because in future you can
implement an Iterator on class and alter iteration behavior.
But after reading through https://externals.io/message/103718 and
https://github.com/phpstan/phpstan/issues/1060 I can see how this
behavior can lead to bugs if the developer didn't intend the object to
be iterated. So a better approach would be to add getIterator to all
my DTOs
public function getIterator(): Traversable
{
return new ArrayIterator($this);
}
But ArrayIterator is a lot slower than simple object iteration (2.4
times slower with only public properties in the object and 1.5 times
slower with some private/protected properties). It would be nice if
there was some lightweight ObjectIterarotor designed to work with
object properties.
Also some note in docs to discourage usage of object iteration would
be good https://www.php.net/manual/en/language.oop5.iterations.php
ΠΏΡ, 15 Π½ΠΎΡΠ±. 2024β―Π³. Π² 02:30, Gina P. Banyard internals@gpb.moe:
Am 14.11.2024 um 10:59 schrieb Marco Pivetta ocramius@gmail.com:
Hello, Internals!
As you know if you try to unpack a regular object (
...$object
) you will get an error: Only arrays and Traversables can be unpacked.
I don't really see a reason for this restriction, because foreach on objects works perfectly fine, so I made a feature request on GitHub to change this behavior (https://github.com/php/php-src/issues/16038) and was advised to see opinions on this here.
So, what do you think? And does this change require RFC?TBH, foreach on objects is already quite an abomination in itself π¬
It is a bit less weird if you use value objects or json data in object form.
I would be careful to judge how other people use the language, just saying ;-)
- Chris
Judging how one should use a language is a core component of language design.
I'm with Marco on this one, and I'd be more than happy to get rid of foreach($object), too. It's way, way more complicated a topic than you think.
How does visibility play into it?
Should hooks be invoked or no?
Do references play into anything?Those are some of the questions we had to deal with for hooks and foreach(). It's non-trivial. You'd need to address all the same edgy issues here, too.
And that's assuming it's even a good idea, which I don't think it is. If you are using a value object to define unordered arguments, just pass the value object itself. If the receiving function can't handle that, then it is simple enough that you don't need a value object. If that's not the case, then your code design is bad and the language should not try to paper over that for you. Either simplify the function or adapt it to use a value object directly. (With union types you can even do so in a BC fashion much of the time.)
Agreed, this bites us constantly when needing to reason about what an "object" is in PHP.
Similar to array it mixes the concept of a struct, with that of a reference value, and "overloading" various behaviours (e.g. iterators and ArrayAccess).
It is extremely simple to go from foreach ($object as $prop) {} to forearch(get_object_vars($object) as $prop) {}
and mandating this would resolve a lot of complexity, be that from the perspective of what is "possible" or not to do, and from an engine PoV.Best regards,
Gina P. Banyard
Am 14.11.2024 um 22:27 schrieb Gina P. Banyard internals@gpb.moe:
Agreed, this bites us constantly when needing to reason about what an "object" is in PHP.
Similar to array it mixes the concept of a struct, with that of a reference value, and "overloading" various behaviours (e.g. iterators and ArrayAccess).
It is extremely simple to go from foreach ($object as $prop) {} to forearch(get_object_vars($object) as $prop) {}
and mandating this would resolve a lot of complexity, be that from the perspective of what is "possible" or not to do, and from an engine PoV.
Is there (currently) a difference between
foreach ($obj ...)
and
foreach (get_object_vars($obj) ...)?
If there is then the migration is not always "extremely" simple, no?
If there isn't then we can simply define that from now on the former is equivalent to the second one and ignore future changes to visibility, hooks etc.
My main point is that over the last years a lot of (for our code unnecessary) complexity was added but I hardly complained because other people have other needs. I just ask for similar consideration in return when stripping stuff.
Regards,
- Chris
Am 14.11.2024 um 22:27 schrieb Gina P. Banyard internals@gpb.moe:
Agreed, this bites us constantly when needing to reason about what an "object" is in PHP.
Similar to array it mixes the concept of a struct, with that of a reference value, and "overloading" various behaviours (e.g. iterators and ArrayAccess).
It is extremely simple to go from foreach ($object as $prop) {} to forearch(get_object_vars($object) as $prop) {}
and mandating this would resolve a lot of complexity, be that from the perspective of what is "possible" or not to do, and from an engine PoV.Is there (currently) a difference between
foreach ($obj ...)
and
foreach (get_object_vars($obj) ...)?If there is then the migration is not always "extremely" simple, no?
If there isn't then we can simply define that from now on the former is equivalent to the second one and ignore future changes to visibility, hooks etc.My main point is that over the last years a lot of (for our code unnecessary) complexity was added but I hardly complained because other people have other needs. I just ask for similar consideration in return when stripping stuff.
There is not, see: https://3v4l.org/T7tSu/rfc#vgit.master
Best regards,
Gina P. Banyard
I absolutely agree that unpacking objects to functions is a bad idea,
my use case for this is different.
Take for example that you have API endpoint that returns user balance
readonly class Balance
{
public function __construct(
public float $debt,
public float $credit,
) {}
}
And a service that do all the logic
interface UserService
{
public function getBalance(): Balance;
}
But you also have endpoint for general user information that includes
flattened balance (better thing would be to just have balance
property, but API already designed and you can't change it)
readonly class Profile
{
public function __construct(
public string $name,
public float $debt,
public float $credit,
) {}
}
So a logical thing to do is just unpack (flatten) balance object
return new Profile(
...$service->getBalance(),
name: $name,
);
ΡΡ, 14 Π½ΠΎΡΠ±. 2024β―Π³. Π² 22:28, Larry Garfield larry@garfieldtech.com:
Am 14.11.2024 um 10:59 schrieb Marco Pivetta ocramius@gmail.com:
Hello, Internals!
As you know if you try to unpack a regular object (
...$object
) you will get an error: Only arrays and Traversables can be unpacked.
I don't really see a reason for this restriction, because foreach on objects works perfectly fine, so I made a feature request on GitHub to change this behavior (https://github.com/php/php-src/issues/16038) and was advised to see opinions on this here.
So, what do you think? And does this change require RFC?TBH, foreach on objects is already quite an abomination in itself π¬
It is a bit less weird if you use value objects or json data in object form.
I would be careful to judge how other people use the language, just saying ;-)
- Chris
Judging how one should use a language is a core component of language design.
I'm with Marco on this one, and I'd be more than happy to get rid of foreach($object), too. It's way, way more complicated a topic than you think.
How does visibility play into it?
Should hooks be invoked or no?
Do references play into anything?Those are some of the questions we had to deal with for hooks and foreach(). It's non-trivial. You'd need to address all the same edgy issues here, too.
And that's assuming it's even a good idea, which I don't think it is. If you are using a value object to define unordered arguments, just pass the value object itself. If the receiving function can't handle that, then it is simple enough that you don't need a value object. If that's not the case, then your code design is bad and the language should not try to paper over that for you. Either simplify the function or adapt it to use a value object directly. (With union types you can even do so in a BC fashion much of the time.)
--Larry Garfield