Skip to main content

PHP Arrays - The php array functions

Source: Xavier33300 on Flickr.com
In my previous article about arrays (the basicssimple operations and associative arrays or hash maps) I have shown what arrays are and what you can do with it. Now I want to dive into real fun and explain PHP's array functions with real-world examples and how you can apply them in your day-to-day work.

Collection to select form key-values

Many of the website registration forms uses a country select element or an autocomplete input field using data from a database.


If this was a single PHP with HTML combined page, there was no problem as you could easily reuse the query made to collect the data. But when using an MVC approach where your controller needs to push the data it fetches from the backend to the form before the form can be passed to the view you're in for a treat. We're addressing the issues for an MVC approach here.

Let's look at our country table first to get an impression how data is being stored in the database.

+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| iso       | char(2)     | NO   |     | NULL    |                |
| name      | varchar(80) | NO   |     | NULL    |                |
| nicename  | varchar(80) | NO   |     | NULL    |                |
| iso3      | char(3)     | YES  |     | NULL    |                |
| numcode   | smallint(6) | YES  |     | NULL    |                |
| phonecode | int(5)      | NO   |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+

In order to use this data in our forms, the two fields "iso" and "printable_name" are most likely the fields that would make the most sense.

Two approaches we can take here:

  1. we query our database for only those fields we need, with the requirement that we need to make a second database call when we need to populate our select field for country phone prefixes
  2. we query all of our required fields "iso", "printable_name" and "phonecode" in one query and use PHP array functions to populate our select fields
We choose to take option 2.

Let's have a look on how most people do things nowadays. The first thing they do is retrieve the data from their backend in the controller. In the controller they prepare their form and pass the form back to the view.

public function registerAction()
{
    
$form $this->getForm('member');

    
$countryMapper = new CountryMapper();
    
$countryList $countryMapper->fetchAll();
    
$countrySelect = [];
    
$phoneSelect = [];
    foreach (
$countryList as $country) {
        
$countrySelect[] = [
            
'iso' => $country['iso'],
            
'nicename' => $country['nicename'],
        ];
        
$phoneSelect[] = [
            
'phonecode' => $country['phonecode'],
            
'nicename' => $country['nicename'],
        ];
    }
    
$form->getElement('country')->addMultiOptions($countrySelect);
    
$form->getElement('phoneprefix')->addMultiOptions($phoneSelect);

    if (isset (
$this->session->memberForm)) {
        
$form unserialize($this->session->memberForm);
        unset (
$this->session->memberForm);
    }
    return [
        
'memberForm' => $form,
    ];
}

So, within the controller a loop is created to populate two field elements "country" and "phoneprefix".  Even though this is an easy approach and works in most cases, the moment you have a lot of data to process, this kind of approach is slowing down your application. Say hello to two power functions: "array_walk" and "array_intersect_key"!

PHP function "array_walk" allows you to apply user functionality to each element of that array. This means we can apply our second functionality "array_intersect_key" on each row.

PHP function "array_intersect_key" gives us the ability to take the common elements from our country list row and the keys we provide as second argument.

$countrySelect = [];
array_walk($countryList, function ($row$key) use (&$countrySelect) {
    
$countrySelect[] = array_intersect_key(
        
$row,
        [
'iso' => null'nicename' => null]
    );
});

$phoneSelect = [];
array_walk($countryList, function ($row$key) use (&$phoneSelect) {
    
$phoneSelect[] = array_intersect_key(
        
$row,
        [
'iso' => null'phonecode' => null]
    );
});

Now we have two arrays that contain only the elements we can just pass on to the form select elements. And the whole controller action now looks like this:

public function registerAction()
{
    
$form $this->getForm('member');

    
$countryMapper = new CountryMapper();
    
$countryList $countryMapper->fetchAll();
    
$countrySelect = [];
    
array_walk($countryList, function ($row$key) use (&$countrySelect) {
        
$countrySelect[] = array_intersect_key(
            
$row,
            [
'iso' => null'nicename' => null]
        );
    }); 

    
$phoneSelect = [];
    
array_walk($countryList, function ($row$key) use (&$phoneSelect) {
        
$phoneSelect[] = array_intersect_key(
            
$row,
            [
'iso' => null'phonecode' => null]
        );
    });
    
$form->getElement('country')->addMultiOptions($countrySelect);
    
$form->getElement('phoneprefix')->addMultiOptions($phoneSelect);

    if (isset (
$this->session->memberForm)) {
        
$form unserialize($this->session->memberForm);
        unset (
$this->session->memberForm);
    }
    return [
        
'memberForm' => $form,
    ];
}

Finding primary keys from a collection

Another common pattern I see is when developers need to pull ID's from a collection of elements to pass on to a next request. Again, foreach is the common used loop to iterate over each element, adding the ID property to another array which then gets passed on to the query.

Let's first look our code that we're going to process.

class PhpFunction {
    public 
$id;
    public 
$label;

    public function 
__construct($id$label)
    {
        
$this->id $id;
        
$this->label $label;
    }
$functions = [
    new 
PhpFunction(123'array_map'),
    new 
PhpFunction(124'array_merge_recursive'),
    new 
PhpFunction(125'array_merge'),
];

Now this example is only containing 3 elements, but when you look at the php.net website there are thousands of functions, so consider this is a huge collection of php functions.

In many cases I see something like the following code to retrieve the ID's from this collection:

$functionIds = [];
foreach (
$functions as $function) {
    
$functionIds[] = $function->id;
}

Even though this is a common pattern, I would prefer to use a native PHP function for processing this. Say hello to "array_map", the function that allows you to use a custom functionality on each element of the given array.

$functionIds array_map(function ($element) {
    return 
$element->id;
}, 
$functions);

The result is exactly the same, but now using PHP's native C power processing huge arrays goes a bit faster than the "foreach"-loop.

Next article we're looking at more common patterns for processing arrays. Love to see you again.



Comments

Popular posts from this blog

Speeding up database calls with PDO and iterators

When you review lots of code, you often wonder why things were written the way they were. Especially when making expensive calls to a database, I still see things that could and should be improved.
No framework development When working with a framework, mostly these database calls are optimized for the developer and abstract the complex logic to improve and optimize the retrieval and usage of data. But then developers need to build something without a framework and end up using the basics of PHP in a sub-optimal way.

$pdo = new \PDO( $config['db']['dsn'], $config['db']['username'], $config['db']['password'] ); $sql = 'SELECT * FROM `gen_contact` ORDER BY `contact_modified` DESC'; $stmt = $pdo->prepare($sql); $stmt->execute(); $data = $stmt->fetchAll(\PDO::FETCH_OBJ); echo 'Getting the contacts that changed the last 3 months' . PHP_EOL; foreach ($data as $row) { $dt = new \DateTime('2015-04-…

Deploy Docker containers fast to Microsoft Azure

DEPLOY DOCKER CONTAINERS FAST TO MICROSOFT AZURE It’s hard to ignore the fact thatDockeris a way to move forward for rapid application development, distributed architectures and microservices. For developersDockeroffers great advantages as they can build their containers specifically for the task they work on. They grab a base image of a container, modify it for their purpose and prepare the functionality inside the container. Quality, testing and security teams now have a single instance to look at and ensure all functional and regulatory requirements are met. System engineers now don’t have to worry about providing a system with the required specs as the container is already provisioned for that purpose. But where do you deploy yourDockercontainers? You can set up your existing bare metal infrastructure to allow them to run containers, but this also means you need to learn about securing your container infrastructure, which is not an easy task. Luckily “the cloud” offers container …

PHP Arrays - Associative Arrays or Hash Maps

Associative array or hash maps are listings of key and value pairs with a posibility to nest additional keys and values. An associative array is a very powerful construct within PHP.

In our previous article we discussed simple arrays, which in their turn are indexed associative arrays under the hood. Take the following example:

$array = [
'apple',
'banana',
'chocolate',
]; 

Is in fact an indexed associative array under the hood:

$array = [
0 => 'apple',
1 => 'banana',
2 => 'chocolate',
]; 

But associative arrays can be so much more than just an indexed array, and you will find many database operations returning arrays where the fields of a table are the keys in the array while their values are also the values within the array.

$productRowData = [
'product_id' => 1234,
'brand_id' => 321,
'product_name' => 'Our awesome product',
'prodcut_description' => 'This is our most awesome product.&#…