
I have been tormented for a long time by the thought of one problem - the total abuse of arrays in PHP. Perhaps the root of the problem in the procedural legacy of PHP, or that PHP attracts a large number of inexperienced developers, I do not know. But the fact is that many people use arrays where objects should be used!
Let's take a look at a typical example of a horrendous, in my opinion code that abuses arrays. For example, suppose we retrieve data from a database and work with them through an array. These are the examples I see daily:
$ponds = array( array( "name" => "Breakspear", "size" => "large", "pegs" => "23", "amenities" => array( "toilets" => false, "shop" => true, ), "fishBreeds" => array( array( "name" => "Bream", "stocked" => "2013-10-04 12:16:47", "number" => "100", "record" => "5.4lbs", ), array( "name" => "Perch", "stocked" => "2012-02-02 05:23:32", "number" => "50", "record" => "1.2lbs", ), array( "name" => "Common Carp", "stocked" => "2011-01-23 14:42:59", "number" => "10", "record" => "15.4lbs", ), ), ), );
We see a huge multidimensional array that stores information about a particular fishing pond. Only one pond is described here, but imagine what would have happened if there were described a hundred ponds? What is the result? We have a dataset stored in an array, but with no associated behavior. When we need to work with this data, we will have to create complex code, full of nested loops. For example, how can I get the total number of fish in a pond? I will have to go through the whole array and add up the whole amount of fish. For an inexperienced developer, this would not have seemed bad, he would have done it, but I would prefer such an approach:
')
$ponds->getNamed("Breakspear")->getTotalStocked();
Much less code to get the same result. Of course, full brute force cannot be avoided, but the functionality is beautifully encapsulated. Actually, this example and reveals the main problem - you should not avoid the advantages of the PLO. Something like this should look like the code from the first example:
$ponds = new PondCollection(); $pond = new Pond("Breakspear"); $pond->addStockData(new StockData("Bream", 100, "2013-10-04 12:16:47")); $pond->addStockData(new StockData("Perch", 50, "2012-02-02 05:23:32")); $pond->addStockData(new StockData("Common Carp", 10, "2011-01-23 14:42:59")); $pond->addAmenity(new ShopAmenity()); $ponds->add($pond);
Excessive complexity
The use of huge arrays means not only the impossibility of adding related behavior, but also obliges to create complex data access mechanisms. Often this is implemented as multifunctional classes with healthy methods using nested loops. Like this
foreach ($ponds as $pond) { foreach ($pond["fishBreeds"] as $breed) { $stockedFish += $breed["number"]; } }
Writing and maintaining such code is difficult, especially if there is any change in the data structure. In addition, the implementation of the methods has nothing to do with the data it uses.
Using classes for encapsulation it may seem that the code eventually has to write more, but I guarantee from my own experience that this will result in lower costs in the future. Just think, you don’t have to write a new cycle each time to search for values. There will be less code, it will be cleaner, you will see clear boundaries of what each class does.
You do it wrong
The only reasons why developers continue to write such code is either inexperience or being lost in a procedural past. The PLO was invented just for this sort of thing, especially for associating behavior with a state. Believe it or not, I have seen the code of a very popular e-commerce company using this anti-pattern for such important parts as the shopping cart and orders. There are places in the code that the developers simply forbid to touch (despite the presence of bugs) because the code is very complicated and fragile, because the changes are simply impossible. Madness.
Work with datasets
Throw out of my head that you need to use arrays to work with a dataset. A “data set” (or collection) does not mean the use of arrays! Inexperienced developers do this because they have not heard about iterators. Using them allows you to work with collections, implementing a specific behavior. At first glance, it is difficult, but in reality everything is simple. Here is the class that implements the iterator
class PondsCollection implements IteratorAggregate { private $collection = array(); public function getIterator() { return new ArrayIterator($this->collection); } public function add($pond) { $this->collection[] = $pond; } }
That's all. An implementation of a class that creates an iterable collection of data combined with behavior. In its heart class contains an array, but which is now decorated with appropriate methods for working with data. The implementation of the IteratorAggregate interface makes the class object available for working with the loop.
$ponds = new PondsCollection(); $ponds->add(...); foreach ($ponds as $pond) { ... }
Now there is no need in every place where we need to get data from the set to implement the associated behavior, it will be associated with the collection of data and available from the object, rather than scattered throughout the code.
Details in the documentation: