-
-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add each
method to the ArrayCollection
#87
Comments
BC compat, mostly. Collection interface is closed for modification. |
Why not start implementation and add the method to the interface on next major? |
It would be interesting, but it would also have a high impact on the ecosystem, making upgrades very painful. |
Why? Just one method to add for people implementing the interface directly, nothing to do for people using doctrine classes.
Which kind of redesign? BTW, if you don't want to create a new major right now, you can implement the Then when you will release the next major, uncomment the method. Not a very beautiful method, but this is the best way we found on sonata projects for now (cc @greg0ire @core23). |
We looked a lot at things like https://github.com/morrisonlevi/Ardent - the collection API needs some sort of differentiation between dictionaries, arrays, stacks, linked lists, etc. The reason behind that being that the current logic is all crammed together into a single object that is just PHP arrays (again, sigh).
If we do that, people will start relying on a concrete implementation rather than an abstraction, and that would be more harmful to the ecosystem |
Alternatively, you can add a new interface, and merge it with the other on next major (or keep it separate if it makes sense). |
@soullivaneuh all the Doctrine |
So I see two solutions:
|
I was Actually thinking of doing this on next minor interface NewInterface
{
public function newMethod();
}
class ArrayCollection implements NewInterface, OldInterface
{
} And optionally do this on next major, if keeping several interfaces makes no sense (Does Interface Segregation Principle apply here ?) interface OldInterface
{
// other methods…
public function newMethod();
}
class ArrayCollection implements OldInterface
{
} I can see how this is not great because NewInterface would be sort of instantly deprecated Client code would then look like this : public function myMethod(OldInterface $collection)
{
// do some stuff
if ($collection instanceof NewInterface) { // this line is not forward-compatible :(
// yaaaay, can use new method
} else {
// old method, to be removed on next major when we rely on doctrine/collection ^$nextMajor
}
} Problem : this is not very compatible with deprecation warnings and smooth upgrade, unless you deprecate |
If an "each" method does get added, it might be worth adding other helper methods. For example: // implementation
public function sum(Closure $p)
{
$sum = 0;
$this->each(function($key, $element) use ($p, &$sum) {
$sum += $p($key, $element);
});
return $sum;
} // usage
$sum = $this->collection->sum(function($key, $element) {
return $element->getSomeValue();
}); Although, this "sum" helper is only a slight improvement over: $sum = 0;
$this->collection->each(function ($key, $element) use (&$sum) {
$sum += $element->getSomeValue();
}); |
Hey @taylankasap ! I think the method your looking for is name The method should be named |
Any utility methods taking a closure as argument would be methods that cannot be implemented in optimized way by persistent collections (as the closure can do anything). And so having them in the Collection interface does not have much benefits over having a separate function taking the collection and the callable. so I would not be in favor of adding such utilities in the Collection interface. |
There are however a You can write
But have to
It's not consistent :/
It's not like it would be a big major version. |
I would just like to add a note for anyone who see this comment:
|
I feel like it's too bad to not create a new major version with useful method added to the collection interface. There is a method contains, exists or filter and a method first, but no method find, which could be more performant. It could also avoid some usage of the 'toArray' method. For example if we add a reduce method. |
That's an issue we have both in Doctrine and Sonata: major versions are a big deal. They wouldn't be if we had them more frequently (or at all, really). |
I saw multiple PR on master, so I took all my hopes and create one too with the methods I find useful: #252. I know doctrine/orm next major is a big deal, but I have trouble to see what is big for doctrine/collections. To me doctrine could
|
I don't see any blocker either :) |
then, the naming is bad. |
A lot of method could be improved. The But the The method |
@VincentLanglet changing existing methods requires BC breaks for packages consuming collections, which is much harder for the ecosystem than BC breaks for packages implementing collections (which is the kind of BC break for adding a new method). So cleaning the existing API would be quite hard. |
I wish PHP had something like extension methods from C#, or maybe the pipe operator would make a deal. |
The Doctrine collection API is completely frozen for years and there won't be any major improvements (even not in 2.0) due to the ecosystem and other Doctrine projects relying on exactly that API according to what @Ocramius, @stof and @greg0ire said. If you want a feature-rich and extensible collection API, you can try the PHP Map package in addition. Converting a Doctrine collection into a Map is just a matter of: $m = map( $collection ); and you have all named methods available (and 100+ more): $v = $m->each(function($val, $key) {
return -$val < 0;
})->reduce(fuction($result, $val) {
return $result + $val;
});
// or use
$v = $m->every(function($val, $key) {
return $val > 0;
})->sum(); You can also extend the Map objects dynamically by your own methods like @someniatko mentioned, e.g. Map::method( 'strrev', function( $sep ) {
return strrev( join( '-', $this->list ) );
} );
Map::from( ['a', 'b'] )->strrev( '-' ); You can even operate on all objects in a map at once: // MyClass implements setId() (returning $this) and getCode() (initialized by constructor)
$map = Map::from( ['a' => new MyClass( 'x' ), 'b' => new MyClass( 'y' )] );
$map->setStatus( 1 )->getCode()->toArray(); The full documentation of the PHP Map package is available at https://php-map.org/ |
Is there a reason for not adding it?
The text was updated successfully, but these errors were encountered: