A Tale of Fox and Hens Getting a Cure May 7, 2020

How do you create an array of pointers to other pointers in PHP? Or you'd like to hear a story first?

In an alternate universe, foxes and hens get along just fine. Unfortunately for them, there is a virus spreading around, much like the corona virus in our world. A recently developed injection might present a cure; however, without a controlled trial, it is difficult to tell whether the medication is effective.

Applying the treatment is simple. Administering the cure in a scientific manner, on the other hand, can be challenging. As we take care of our friends on the farm, we will also get to know more about how PHP handles pointers and objects.

First let's meet the fox and hens:

$fox=array(

    'name'=>'Joey'

);

$henhouse=array(

    array('name'=>'Otis'),

    array('name'=>'Ingrid')

);

The treatment aims to modify the subject in the following way:

$fox['cured']=1;

The cure is compatible to both foxes and hens, so we could use the same function:

function cure($obj){

    $obj['cured']=1;

}

cure($fox); print_r($fox);

The output is

Array
(
    [name] => Joey
)

The $fox is not cured! This is because when an object is passed to a function, a copy is made. We can prevent copying by passing a reference instead:

function cure(&$obj){

    $obj['cured']=1;

}

Upon running the new cure on the fox, we get the following:

Array
(
    [name] => Joey
    [cured] => 1
)

Great, now we can do the same to every chicken in the hen house:

foreach ($henhouse as $chick){

    cure($chick);

}

print_r($henhouse);

To our surprise, nobody inside the house seems to be touched:

Array
(
    [0] => Array
        (
            [name] => Otis
        )

    [1] => Array
        (
            [name] => Ingrid
        )

)

This is because PHP also makes a copy of each object inside a loop. There is an elegant way to avoid copies:

foreach ($henhouse as $k=>$chick){

    cure($henhouse[$k]);

}

Although "$henhouse[$k]" and $chick carry the same value to start with, $henhouse[$k] is the original, whereas $chick is just a replica.

Now that we have a quick way to apply the cure, we would like to deploy the solution to other farms:

function cure_farm(&$fox, &$henhouse){

    cure($fox);

    foreach ($henhouse as $k=>$chick){

        cure($henhouse[$k]);

    } //foreach

}//func

The above function works. But how do we know that the treatment has no long term harm? One other special thing about this universe is that sub parallel universes can be easily created as snapshots. We can keep a copy of the old fox and hens, and let the cured ones run in a hypothetical realm:

$fox_copy=$fox;

$henhouse_copy=$henhouse;

cure_farm($fox, $henhouse);

//save $fox_copy and $henhouse_copy to the database

Now we are at a point of discussing code safety. If not careful, one can easily save the modified copy to the database. We'll need access to both the original and the cured populations. It is not uncommon to see the following code:

//save $fox and $henhouse to the database

cure_farm($fox, $henhouse);

//everyone is cured from now on

The above code is still unsafe. It would be more obvious if the function returns a copy:

function cure_farm($fox,$henhouse){

    cure($fox);

    cure($henhouse);

    return array(

        'fox'=>$fox,

        'henhouse'=>$henhouse

    );

}

$cured=cure_farm($fox, $henhouse);

Now we can easily tell the cured fox from the uncured one:

$fox; //original

$cured['fox']; //cured

What if we would like to merge the cure function with the cure_farm function?

function cure_farm($fox,$henhouse){

    $fox['cured']=1;

    foreach ($henhouse as $k=>$chick)

        $henhouse[$k]['cured']=1;

    return array(

        'fox'=>$fox,

        'henhouse'=>$henhouse

    );

}

Since our cure is trivial, it doesn't seem like a big deal to duplicate the code. If the cure involves many lines of code, how can we merge the loop?

function cure_farm($fox,$henhouse){

    $objs=array(&$fox); //pointer to a COPY of the fox

    foreach ($henhouse as $k=>$chick){

        $objs[]=&$henhouse[$k];

    }

    //merged array

    foreach ($objs as $k=>$obj){

        $objs[$k]['cured']=1;

        //there could be many more lines...

    }

    return array(

        'fox'=>$fox,

        'henhouse'=>$henhouse

    );

}

Now that all the farms can be cured and test-cured, we can leave their universe with the following gem:

So far, we've seen how to make an array of pointers that point to elements to clones of other collections that are implicitly cloned through the passing function arguments. Not only were we introduced a magic spell, but also were we shown when we should use it.

Our Services

Targeted Crawlers

Crawlers for content extraction, restoration and competitive intelligence gathering.

Learn More

Gyroscope™ ERP Solutions

Fully integrated enterprise solutions for rapid and steady growth.

Learn More

E-Commerce

Self-updating websites with product catalog and payment processing.

Learn More