Arrayable Interface

817 views
Skip to first unread message

Barry vd. Heuvel

unread,
Nov 1, 2014, 2:10:26 PM11/1/14
to php...@googlegroups.com
Hello all,

I appreciate all the hard work you guys are doing to improve the PHP experience for all of us and know you are busy with some 'large' proposals (Cache/Request etc) but I hope this would be interesting for you guys. If not (or this has already been proposed/rejected) or this is the wrong place to ask, my apologies.

Proposal: Arrayable Interface

TLDR: I propose creating 1 interface (Psr\Arrayable) with 1 method (toArray()) which returns the array value of the object.

Situation:
A lot of projects are using toArray() on objects to get the array representation of that object. Some projects define an interface for this, others have this method as part of a different interface and others just have a toArray() option.
There currently is no standard for this, although there was talk of a __toArray() method in an RFC: https://wiki.php.net/rfc/object_cast_to_types but that is inactive
There is a PHP interface (JsonSerializable::jsonSerialize) for returning data that can be passed to json_encode() which is probably most of the time the same, but that can't always be used and sometimes isn't the same.

Problem:
Everyone is creating their own interface and they are also checking against that implementation ($data instanceof MyArrayableInterface). So the toArray functionality isn't easily shared between components. (You could check if the method exists but that doesn't guarantee the expected result)

Solutions:
Create a PSR for a Arrayable interface, so frameworks/libraries could use that, instead of their own interface. Objects that provide toArray() could just implement that interface.

Current usage:
I've checked a couple of libraries and many seem to use this. PHP itself also has some methods called toArray() so there seems to be a general consensus about the method name already. But there are some interfaces that have different names (getArrayCopy) or extra parameters ($fields etc). And perhaps some frameworks don't use it at all or have some very different name so I couldn't find them quickly ;)

Examples:

With different name/parameters:


To finalize, this probably shouldn't need to be more then the Arrayable interface from Laravel (https://github.com/illuminate/contracts/blob/master/Support/Arrayable.php), but perhaps a toJson() could also be considered.

I'm not a voting member or prominent member of any large framework, but I'd be happy to help / do some research or something, but I'd be just as happy if a member would take this into consideration :)

Thanks and keep up the good work!

Barry vd. Heuvel

Larry Garfield

unread,
Nov 2, 2014, 12:59:12 PM11/2/14
to php...@googlegroups.com
On 11/01/2014 01:10 PM, Barry vd. Heuvel wrote:
Hello all,

I appreciate all the hard work you guys are doing to improve the PHP experience for all of us and know you are busy with some 'large' proposals (Cache/Request etc) but I hope this would be interesting for you guys. If not (or this has already been proposed/rejected) or this is the wrong place to ask, my apologies.

This is an entirely reasonable place to make such proposals, and I don't believe anyone has made this one before. Hi there. :-)


Proposal: Arrayable Interface

TLDR: I propose creating 1 interface (Psr\Arrayable) with 1 method (toArray()) which returns the array value of the object.

The key question here, I think, is whether or not such an interface would, in practice, improve interoperability. Yes, lots of systems have variations on toArray().  Does the lack of them hinder code reuse between projects?  Honestly I've not run into a case where it does, so I don't see much benefit to such an interface.  Has anyone else seen a problem with reusing toArray() between projects?

--Larry Garfield

Paul M. Jones

unread,
Nov 2, 2014, 1:05:54 PM11/2/14
to php...@googlegroups.com

> Proposal: Arrayable Interface
>
> TLDR: I propose creating 1 interface (Psr\Arrayable) with 1 method (toArray()) which returns the array value of the object.

I like the idea, although the name itself could use some work, especially if we introduce other formats (see below).


> Current usage:
> I've checked a couple of libraries and many seem to use this. PHP itself also has some methods called toArray() so there seems to be a general consensus about the method name already. But there are some interfaces that have different names (getArrayCopy) or extra parameters ($fields etc). And perhaps some frameworks don't use it at all or have some very different name so I couldn't find them quickly ;)
>
> Examples:
> http://php.net/manual/en/httpquerystring.toarray.php
> https://github.com/doctrine/collections/blob/master/lib/Doctrine/Common/Collections/Collection.php
> https://github.com/illuminate/contracts/blob/master/Support/Arrayable.php
> https://github.com/thephpleague/fractal/blob/master/src/Scope.php
> https://github.com/zendframework/zf2/blob/master/library/Zend/Config/Config.php
> https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Debug/Exception/FlattenException.php
>
> With different name/parameters:
> https://github.com/zendframework/zf2/blob/master/library/Zend/Stdlib/ArraySerializableInterface.php
> https://github.com/yiisoft/yii2/blob/master/framework/base/Arrayable.php

I applaud your research -- well done, and good form!

I see you have SPL ArrayObject::getArrayCopy( <http://php.net/manual/en/arrayobject.getarraycopy.php> listed; I think it deserves somewhat more prominence, but you have definitely included it, which is good.

I can see where having a whitelist would be useful, although I suggest it may be best to leave that out of the interface here.

> perhaps a toJson() could also be considered.

(/me nods) getJsonCopy(), getXmlCopy(), etc. might be useful. But then it's not "Arrayable" per se.

There's also the asArray()/asJson()/etc. variations to be considered, but those appear to be less common per your research:

- asArray(): https://github.com/search?utf8=%E2%9C%93&q=function+asArray+language%3APHP+extension%3A.php&type=Code&ref=advsearch&l=PHP>

- toArray(): <https://github.com/search?utf8=%E2%9C%93&q=function+toArray+language%3APHP+extension%3A.php&type=Code&ref=searchresults>

Again, nicely done. Consider me interested.


--
Paul M. Jones
pmjo...@gmail.com
http://paul-m-jones.com

Modernizing Legacy Applications in PHP
http://mlaphp.com



Paul M. Jones

unread,
Nov 2, 2014, 1:07:17 PM11/2/14
to php...@googlegroups.com

> The key question here, I think, is whether or not such an interface would, in practice, improve interoperability. Yes, lots of systems have variations on toArray(). Does the lack of them hinder code reuse between projects? Honestly I've not run into a case where it does, so I don't see much benefit to such an interface. Has anyone else seen a problem with reusing toArray() between projects?

I have not. Even so, I think the idea of "discovering common practices and codifying them" is both sensible and within the scope of this group.

Barry vd. Heuvel

unread,
Nov 2, 2014, 2:24:28 PM11/2/14
to php...@googlegroups.com
I like the idea, although the name itself could use some work, especially if we introduce other formats (see below).
 
The name is just an example :) But if other formats are introduced, perhaps an interface should be provided for each format instead of combining them to a 'one-fits-all' interface.
 

Crypto Compress

unread,
Nov 2, 2014, 3:00:02 PM11/2/14
to php...@googlegroups.com
Hello List,

all "toFooBar()" methods have a inherent/common misconception: the lack
of context. They are *only* usefull in a specific context and should not
be generalized (as context-free interface). Establish a fixed context
will interfere with other valid usecases.

cryptocompress

Pádraic Brady

unread,
Nov 2, 2014, 3:36:10 PM11/2/14
to php...@googlegroups.com
My main concern would be identifying the benefit and then explaining how it improves on method_exists(). An interface with a single method will always face that one ;).

It's self evident that many classes use toArray() for the obvious purpose, but that is not in and of itself a justification for an interface out of context. I can't think of any instances off hand where it would have an impact on interoperability, good or ill.

Paddy



--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/54568D3C.1090800%40googlemail.com.

For more options, visit https://groups.google.com/d/optout.



--

--
Pádraic Brady

http://blog.astrumfutura.com
http://www.survivethedeepend.com
Zend Framework Community Review Team
Zend Framework PHP-FIG Representative

Barry vd. Heuvel

unread,
Nov 2, 2014, 4:21:50 PM11/2/14
to php...@googlegroups.com

My main concern would be identifying the benefit and then explaining how it improves on method_exists(). An interface with a single method will always face that one ;).

It's self evident that many classes use toArray() for the obvious purpose, but that is not in and of itself a justification for an interface out of context. I can't think of any instances off hand where it would have an impact on interoperability, good or ill.

Paddy

Yes toArray() looks pretty obvious and checking if the method exists will probably work in 99% of the cases, if we all agree to name it 'toArray', use no required parameters and return an array as expected. But isn't that what an interface is for, to formalize the method name, parameters and behavior? And in the case of the FIG, so that frameworks could all utilize this interface, instead of having 'asArray', 'toArray', 'getArrayCopy' etc.
(But I do agree, in most cases you would probably have some sort of knowledge about the kind of objects you are and the possible methods on that, except for things like debugging/logging any object or transforming objects based on the array etc)

But if everyone agrees toArray is logical in the name and way it is used, it shouldn't be too hard to formalize that ;)

 
all "toFooBar()" methods have a inherent/common misconception: the lack of context. They are *only* usefull in a specific context and should not be generalized (as context-free interface). Establish a fixed context will interfere with other valid usecases.

cryptocompress

I think toArray() should have to be seen as an alternative to the (not yet existing) __toArray() method, to typecast an object into a more usable array, instead of just doing (array) $object. Context probably isn't very relevant in this case, as it just does what you ask for, get the most appropriate array from the object (because you want to serialize it some other way, or log it or just do some magic on a plain array etc) 


Here are some more examples, including the same interface from Guzzle. Context is all different (but mostly API/Results/DB related) but the idea is the same:


Crypto Compress

unread,
Nov 2, 2014, 4:58:25 PM11/2/14
to php...@googlegroups.com

> Context probably isn't very relevant in this case, as it just does
> what you ask for

Let's try this. What do you expect, if you ask for an array
representation of $foo without knowing the context?
http://3v4l.org/cC9RP

Crypto Compress

unread,
Nov 2, 2014, 5:16:59 PM11/2/14
to php...@googlegroups.com
Maybe an "EnumerableInterface", as this describes behavior, is the idea
behind this proposal? I assume this would include more then one method
and may be valueable for most cases of "api/db result".

cryptocompress

Barry vd. Heuvel

unread,
Nov 2, 2014, 5:24:54 PM11/2/14
to php...@googlegroups.com
I would expect an array with key/values based on what the developer thought what was a good representation of the object, not just returning every parameter from the object. This isn't always useful of course, so this would only be implemented by objects where this makes sense.

An EnumerableInterface would be more like http://php.net/manual/en/class.arrayaccess.php probably? That is not what I meant. I just meant a simple method to get a plain array, as clean as possible.

Crypto Compress

unread,
Nov 2, 2014, 5:40:09 PM11/2/14
to php...@googlegroups.com
Am 02.11.2014 23:24, schrieb Barry vd. Heuvel:
> I would expect an array with key/values based on what the developer thought what was a good representation of the object, not just returning every parameter from the object. This isn't always useful of course, so this would only be implemented by objects where this makes sense.
>
> An EnumerableInterface would be more like http://php.net/manual/en/class.arrayaccess.php probably? That is not what I meant. I just meant a simple method to get a plain array, as clean as possible.
>

Best analogy seems this one:
http://php.net/manual/en/class.traversable.php

Crypto Compress

unread,
Nov 2, 2014, 6:22:42 PM11/2/14
to php...@googlegroups.com
> ...an array with key/values based on what the developer thought what was a good representation of the object...
https://wiki.php.net/rfc/debug-info
Maybe this is close enough to your usecase?

Dracony

unread,
Nov 2, 2014, 10:29:31 PM11/2/14
to php...@googlegroups.com
My main concern would be identifying the benefit and then explaining how it improves on method_exists(). An interface with a single method will always face that one ;).
You can't type hint a method_exists()

To be honest I fail to see how will such an interface facilitate any interpolation between projects since such conversions are usually internal for projects. If there exist methods that would allows such Arrayable interfaces as parameters, why not just make those methods accept actual arrays and call the toArray() beforehand ?

But if FIG rolls with this I think you should consider naming the method __toArray() akin to __toString(). Then maybe someday we could have a RFC to actually add that magic method to PHP. Being able to do $array = (array) $smth; would be really useful, especially if it would do automatic conversions for foreach.

Hari K T

unread,
Nov 2, 2014, 11:28:04 PM11/2/14
to php...@googlegroups.com
Reading many of the comments expressed here I believe this will be useful.

Eg : Now you can do 

if (SomeObject instanceof ArrayInterface) {
   // you know toArray will work
}

May be some of you like explicit type casting though.

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Larry Garfield

unread,
Nov 3, 2014, 1:06:28 AM11/3/14
to php...@googlegroups.com
On 11/02/2014 09:29 PM, Dracony wrote:
> But if FIG rolls with this I think you should consider naming the
> method __toArray() akin to __toString(). Then maybe someday we could
> have a RFC to actually add that magic method to PHP. Being able to do
> $array = (array) $smth; would be really useful, especially if it would
> do automatic conversions for foreach.

function and method names beginning with two underscores are reserved
for PHP internals magic. Trying to pw0n that pattern in the hopes of
internals later doing something that would coincidentally make it work
the way we want in the future is a fools errand, a violation of PHP
conventions, and would probably make internals laugh at us. :-) Let's
not do that.

--Larry Garfield

Barry vd. Heuvel

unread,
Nov 3, 2014, 2:59:33 AM11/3/14
to php...@googlegroups.com
@Crypto Compress
I would expect debugInfo to return more information then what I would expect from toArray(). toArray would probably be something like http://php.net/manual/en/arrayobject.getarraycopy.php
Most useful for object that don't have a 1:1 mapping for their properties to what they want to give as output. For example, something like this: http://3v4l.org/3EWEj


Regarding extra parameters to the toArray method, I would suggest that the interface doesn't have any parameters, but specific implementations could still add optional parameters without breaking the interface.

And maybe that it doesn't necessarily always improve interopterability, it could avoid code duplication (as there are multiple similar interfaces already) or differentation (other method names)



Op maandag 3 november 2014 07:06:28 UTC+1 schreef Larry Garfield:

Dracony

unread,
Nov 3, 2014, 4:51:59 AM11/3/14
to php...@googlegroups.com
Actually now I think that it is in fact a good idea to try to pitch __toArray to internals first. If it passes, and it srrms like it could we wont need to interface it.

If toArray os standardized and then in the future __toArray becomes available we'll just create confusion.

Barry vd. Heuvel

unread,
Nov 3, 2014, 5:17:30 AM11/3/14
to php...@googlegroups.com
It was pitched to internals, see the mentioned RFC: https://wiki.php.net/rfc/object_cast_to_types and this issue: https://bugs.php.net/bug.php?id=38508

I'm not sure what happened to the RFC, but the response from internals to the issue is 'Why not simply have a method asArray() maybe even as par of an interface'

On the internals mail list, I found (among others) these discussions: 
http://markmail.org/thread/p2glh5u6c472cg26 (ArraySerializable interface proposal)
http://markmail.org/thread/yl4fuo7rw35cny5o (About casting, which suggests that __toArray() has been suggested many time and been rejected)

All responses seem to suggest that Internals rather has a userland implementation to toArray() (or similar) instead of building this in the core. And this again shows how common this usage is.


Op maandag 3 november 2014 10:51:59 UTC+1 schreef Dracony:

Dracony

unread,
Nov 3, 2014, 8:09:44 AM11/3/14
to php...@googlegroups.com
What about the actual need for this? Would it actually make anything interpolable with anything else? I don't think that there would be many functions that would typehint against the Arraybale thing, because in that case it's more logical to accept an array.
I think that actual interpolation and "need" should be what FIG works on. Otherwise we'll end up with standards for every little thing there.

On Saturday, November 1, 2014 7:10:26 PM UTC+1, Barry vd. Heuvel wrote:

Crypto Compress

unread,
Nov 3, 2014, 1:05:08 PM11/3/14
to php...@googlegroups.com
Hello Barry,

> I would expect debugInfo to return more information then what I would
> expect from toArray().

In fact it's very easy to rediscover debug hell by reducing output
information with this function, as there is no possibility to bypass it.

Back on topic:

> toArray would probably be something
> like http://php.net/manual/en/arrayobject.getarraycopy.php
> Most useful for object that don't have a 1:1 mapping for their
> properties to what they want to give as output. For example, something
> like this: http://3v4l.org/3EWEj

To (recursive) dump a string representation you can use __toString().
Can not see any behaviour worth an interface in this example.


> Regarding extra parameters to the toArray method, I would suggest that
> the interface doesn't have any parameters, but specific
> implementations could still add optional parameters without breaking
> the interface.

This is not possible.
http://3v4l.org/001C5
http://3v4l.org/6eO4S


> And maybe that it doesn't necessarily always improve
> interopterability, it could avoid code duplication (as there are
> multiple similar interfaces already) or differentation (other method
> names)

Quite right observation and there are indeed ways to solve this:

* intern logic: Move all the logic using "$foo->toArray()" to specific
method(s) of $foo.
This way you implement the behaviour on the proper object and train
encapsulation at it's best.
(and likely to discover the real interface: FooBehaviourInterface /
MyMethodOnFooInterface)

* extern logic: Use explizit named getters: $table->getRows() /
getArrayOfInts()
as opposed to checks and guesses around toArray() returning "array of
objects" or "array of floats" or?
This way all your data objects can stay context agnostic. No need to
imply the outer context.

Bonus: Assume all such generic interfaces are code smell and delete them. :)


cryptocompress

Barry vd. Heuvel

unread,
Nov 3, 2014, 1:35:19 PM11/3/14
to php...@googlegroups.com
Hello Crypto Compress,

I'm not sure if this goes against best practices, but optional parameters do seem to work: http://3v4l.org/evf92

I'm not sure what you mean with the __toString() reference. __toString() is an internal method and therefore doesn't need any interface. No method for casting to an array is defined, so an Interface could be use the explicitly define the behaviour of this method.

And remember, I'm not suggesting that we all stop what we are doing now and go and add toArray() methods on everything or that this is a best practice. I merely noticed that a lot of projects (also from the FIG) are using toArray() or similar methods, and even the same interfaces. And it does come up as a question/proposal regularly. 
And because of the aims of the FIG ('The idea behind the group is for project representatives to talk about the commonalities between our projects and find ways we can work together.') it might be useful to create this simple interface for this purpose.

But that is up to the members of the FIG, as there would first need to be 2 sponsors and then an entrance vote to see if anyone cares at all.

Op maandag 3 november 2014 19:05:08 UTC+1 schreef Crypto Compress:

Crypto Compress

unread,
Nov 3, 2014, 2:11:38 PM11/3/14
to php...@googlegroups.com

I'm not sure if this goes against best practices, but optional parameters do seem to work: http://3v4l.org/evf92

Example: I have a contract with the fruiterer to deliver 100 apples each week. Now i call and ask for 100 pears instead, without changing the contract. May contractor deliver me bananas? ;)



I'm not sure what you mean with the __toString() reference. __toString() is an internal method and therefore doesn't need any interface. No method for casting to an array is defined, so an Interface could be use the explicitly define the behaviour of this method.

You can implement the "print_r() / dump to string" direct on Item and ItemCollection within __toString() as this was the only purpose of whole example.



And remember, I'm not suggesting that we all stop what we are doing now and go and add toArray() methods on everything or that this is a best practice.I merely noticed that a lot of projects (also from the FIG) are using toArray() or similar methods, and even the same interfaces. And it does come up as a question/proposal regularly.

Shure, i insist on not using this methods at all. There are proper alternatives im my last mail.



And because of the aims of the FIG ('The idea behind the group is for project representatives to talk about the commonalities between our projects and find ways we can work together.') it might be useful to create this simple interface for this purpose.

Your work on finding all occurrences and starting this discussion may indeed be very helpful. Not to create even more interfaces but to get ride of all them all together.



But that is up to the members of the FIG, as there would first need to be 2 sponsors and then an entrance vote to see if anyone cares at all.

Please think about it, independent of the FIG, for a second:

Barry vd. Heuvel

unread,
Nov 4, 2014, 3:40:39 AM11/4/14
to php...@googlegroups.com
I'm not sure if this goes against best practices, but optional parameters do seem to work: http://3v4l.org/evf92
Example: I have a contract with the fruiterer to deliver 100 apples each week. Now i call and ask for 100 pears instead, without changing the contract. May contractor deliver me bananas? ;)

That isn't a proper analogy. I was talking about implementing toArray() as part of the interface. And as long as the default behavior of toArray() when called without parameters returns the array as expected, it doesn't necessarily break the interface.
Whether  this is confusing or not is another question. I just brought this up because some methods indeed have some optional parameters, which could add some extra flexibility (if the type is checked to the actual implementation, not the Arrayable interface)

I'm not sure what you mean with the __toString() reference. __toString() is an internal method and therefore doesn't need any interface. No method for casting to an array is defined, so an Interface could be use the explicitly define the behaviour of this method.
You can implement the "print_r() / dump to string" direct on Item and ItemCollection within __toString() as this was the only purpose of whole example.

I hope you understand that the purpose of that example is not being able to do a print_r on the object, but the print_r is merely there to illustrate the different between (array) $item and $item->toArray()
 

Thanks for your feedback, I understand you're not a fan of this and for many cases you are probably right that there are other (/better) alternatives. Your feedback has been noted :)

I do still think that for some cases this might be useful, but let's agree to disagree ;)

Reply all
Reply to author
Forward
0 new messages