php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #72579 Support (array)-casting for objects
Submitted: 2016-07-11 20:39 UTC Modified: 2016-07-24 06:18 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: geiger at karim dot email Assigned:
Status: Suspended Package: Class/Object related
PHP Version: Next Major Version OS:
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: geiger at karim dot email
New email:
PHP Version: OS:

 

 [2016-07-11 20:39 UTC] geiger at karim dot email
Description:
------------
Hi there,

I recently stumbled upon the request #52583 (magic __toArray() for objects) while searching for a way to cast an object containing a list of items to an array for using it on functions like array_map().

There are many options to get to where I want to be, for example implement an interface having a toArray() method, but all of that is quite inconsistent, I think.

I can see how having yet another magic __toArray()-method may not be a good thing, since it just raises more questions and problems, so I'd rather suggest something, which I think is the next logical step.

As you all know, we are already able to implement interfaces like ArrayAccess, Countable, and Iterator. If we've done all that, we're almost where we want to be: Having an object act like an array. We now are able to use it in a foreach loop, assign, unset and alter values using the array-syntax ($foo[] = 'bar';), etc. The only thing that does not work is casting it to an array. If we do so, we'll always get an key-value-pair of its properties. I can see where that's useful, but if we already have all that methods on that object (offset*, next, key, valid, ...), why don't we use them?

I'm suggesting the following behaviour: If a plain object with no interfaces gets casted to an array, maintaining the key-value-conversion is a great idea. But, if the object implements the (or a) Iterator-interface, why can't we "foreach" through that object and combine its keys and values in a true array, making it compatible to all (PHP)-functions and the array type?

I hope this isn't a duplicate entry of some other feature request I didn't find. If not, I'd love to hear your opinion on this and if you think this makes sense.

Best regards

Karim

Test script:
---------------
Since this example implements the Iterator interface, it's a bit too long to paste here. You can visit the Gist at:

https://gist.github.com/KarimGeiger/e3e4fbc4a1ec8c6564347b8a2a217334

Expected result:
----------------
array(2) {
  'foo' =>
  string(3) "bar"
  'baz' =>
  int(123)
}

Actual result:
--------------
array(1) {
  '\0*\0items' =>
  array(2) {
    'foo' =>
    string(3) "bar"
    'baz' =>
    int(123)
  }
}

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-07-11 20:58 UTC] requinix@php.net
-Status: Open +Status: Feedback -Package: *General Issues +Package: Class/Object related
 [2016-07-11 20:58 UTC] requinix@php.net
How about iterator_to_array()? http://php.net/iterator-to-array
 [2016-07-11 21:08 UTC] geiger at karim dot email
Thanks for the quick response. I didn't know that function and it does pretty much what I intend to do, but the problem is: I have to call it manually. I'd love to see that function being invoked automatically when casting to an array, since that's the point of having a cast option after all. In my mind it's not consistent to be able to foreach through an object as expected but getting something completely different when casting it to an array.
 [2016-07-11 21:12 UTC] nikic@php.net
iterator_to_array() has two modes: It can either preserve the keys of the iterator, or it can reindex it. It depends on the iterator which of these behaviors is appropriate. Especially with generator functions it's very common that preserving keys will yield a result of limited usefulness, as duplicate keys are overwritten.

If (array) were to automatically invoke iterator_to_array() in one of these modes, you'd probably end up with the wrong behavior half the time.
 [2016-07-12 06:23 UTC] geiger at karim dot email
I see preserving keys could be a problem and there should be a way to create an array out of the values of an object only, like iterator_to_array($foo, false) does, but nevertheless, I think that "losing" duplicate keys can be seen as expected behaviour when casting to an array, since there are by definition no duplicate keys in an array.

Take this example: $a = (int)3.14;

What's $a going to be? Obviously, it'll result in a flat 3, because an integer just does not support decimals, and that's okay, since it is by fact an integer. Arrays in PHP don't support duplicate keys, hence, you won't get them and they'll be "lost". What arrays in PHP do support, are non-numeric keys, which means, you will get them. In my opinion, you have to deal with things like that manually if you're trying to cast one type to another.
 [2016-07-24 04:22 UTC] php-bugs at lists dot php dot net
No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Re-Opened". Thank you.
 [2016-07-24 06:18 UTC] requinix@php.net
-Status: No Feedback +Status: Suspended
 [2016-07-24 06:18 UTC] requinix@php.net
What @nikic might be getting at is that an array cast using iterator_to_array() is not very obvious in how it would work.

With (int)$float there is very clear behavior which can be seen directly on that line of code: the whole part of $float will be kept and any fractional part will be lost. With (string)$object there is also clear behavior: PHP will try to call $object->__toString().

But with (array)$object it is not clear. Will it call iterator_to_array() or use the default properties-to-array behavior? Does the object/collection potentially have duplicate keys? Will values from duplicate keys overwrite, or will the entire array use numeric keys? Answering those questions requires detailed knowledge about $object that may not be easy to see in its code.

If you like this idea and feel it has merit then you should mention it on the internals mailing list (see http://php.net/mailing-lists.php). At the very least this would be a significant addition to how objects work - to the point where it would have an impact on backwards compatibility (what about code that currently uses an array cast on iterable classes?) - and that alone makes it an issue for discussion and possible RFC.
 [2019-10-29 12:44 UTC] php at shark dot kom dot cz
As requinix@php.net said, automatic conversion with iterator_to_array($foo, false) may break backward compatibility if someone rely on current (array) $foo casting.

But if someone adds __toArray() magic method, than he is in charge of dealing with errors caused by (array) $foo typecasting.

Old code will work same as before without any change.

So I wote for request #52807 which is about to add __toArray() magic method.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 19:01:33 2024 UTC