Instantiating a Namespaced PHP Class Dynamically

It’s pretty well known that you can instante a PHP class with a dynamic name using a variable:

$class = 'Foo_Bar';
$object = new $class();

is the same as

$object = new Foo_Bar();

It gets a little trickier if your class is defined in a namespace and you’re instantiating it from outside of that namespace. If you’re hard-coding a class, you need to use a leading backslash to reference the class.

namespace App;
$object = new \Foo\Bar();

// this would try to instantiate App\Foo\Bar
//$object = new Foo\Bar();

But if you’re using a dynamic name, the string should not have the leading backslash because the backslash is not part of the class name.

namespace App;
$class = 'Foo\Bar';
$object = new $class();

If you include the slash, your code won’t run on PHP 5.3.2 — you’ll get a Class '\\Foo\\Bar' not found error. This stackoverflow post set me straight. As mentioned in the post, the code will work in PHP >= 5.3.3 with or without the slash.

Resetting Whitespace-Only Changes in Git

I used find -exec with sed to do a repository-wide find/replace this morning. Unfortunately, some of the files in the repository didn’t have a newline at the end of the file, but sed added one. I wanted a one-liner to reset all the whitespace-only changes, and I found it on stackoverflow:

git diff -b --numstat \
| egrep $'^0\t0\t' \
| cut -d$'\t' -f3- \
| xargs git checkout HEAD --

Multi-Domain Mail Server with Postfix, Dovecot, Postgrey, DSPAM, and Roundcube

As part of my ongoing infrastructure upgrade project, I recently set up a new mail server on Ubuntu Server 10.04 LTS (Lucid) to replace the old one running Ubuntu 7.04 (Feisty). I know — it’s late 2011, so I’m a year and a half late to the party. Better late than never, right?

For the most part, I followed Christoph Haas’ excellent ISPmail tutorial for Debian Squeeze, but I opted to install Postgrey instead of tumgreyspf and DSPAM instead of SpamAssassin. For the DSPAM install, I mostly followed Colin Stewart’s Postfix, dovecot, dspam and dovecot antispam tutorial.

The rest of this blog post is going to cover the points where I diverged from one of the aforementioned tutorials.

Continue reading

array_merge_recursive() vs. array_replace_recursive()

If you’ve been coding in PHP for a while, you have probably used array_merge() at some point. It’s been around since PHP 4, and like most PHP functions, it does largely what you’d expect it to do. If you have arrays with numeric indices, it re-indexes and appends subsequent arrays to the first array argument.

print_r(array_merge(
    array('a', 'b'),
    array('c', 'd')
));

/* the above will output:
Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => d
)
*/

If you have associative arrays, it doesn’t make much sense to re-index them. Instead, non-numeric keys are … well, merged. Keys from subsequent arrays will overwrite keys with the same name in earlier arrays.

/* note that the key 'B' appears in both arrays */
print_r(array_merge(
    array('A' => 1, 'B' => 2),
    array('B' => 20, 'C' => 30)
));

/* the above will output:
Array
(
    [A] => 1
    [B] => 20
    [C] => 30
)
*/

This is all pretty intuitive. But it gets trickier when you have nested associative arrays to merge. For example, you may have decoded the results from two JSON service calls into arrays, and they both have a top-level data key. array_merge() is not as useful in this case:

print_r(array_merge(
    array(
        'data' => array(
            'collision' => 'first',
            'unique1' => 1,
        )
    ),
    array(
        'data' => array(
            'collision' => 'second',
            'unique2' => 2,
        )
    )
));

/* the above will output:
Array
(
    [data] => Array
        (
            [collision] => second
            [unique2] => 2
        )

)
*/

The first array got clobbered — not quite what you expected, right? Fortunately, there’s a function that will do what you probably want: array_merge_recursive().

print_r(array_merge_recursive(
    array(
        'data' => array(
            'collision' => 'first',
            'unique1' => 1,
        )
    ),
    array(
        'data' => array(
            'collision' => 'second',
            'unique2' => 2,
        )
    )
));

/* the above will output:
Array
(
    [data] => Array
        (
            [collision] => Array
                (
                    [0] => first
                    [1] => second
                )

            [unique1] => 1
            [unique2] => 2
        )

)
*/

In some cases, this behavior isn’t actually what you want. One example is parsing hierarchical config files. If you had a default config and you wanted to merge in a user-specific config, you probably don’t want keys to be merged the way array_merge_recursive() does it. Instead, you would want the user-specific config to replace the default config’s value for that particular key. If you’re running PHP before version 5.3, you’d have to write a custom function to do this. But as of PHP 5.3, there is a new function that does exactly what you want: array_replace_recursive().

print_r(array_replace_recursive(
    array(
        'data' => array(
            'collision' => 'first',
            'unique1' => 1,
        )
    ),
    array(
        'data' => array(
            'collision' => 'second',
            'unique2' => 2,
        )
    )
));

/* the above will output:
Array
(
    [data] => Array
        (
            [collision] => second
            [unique1] => 1
            [unique2] => 2
        )

)
*/

If you’ve written a custom version of array_replace_recursive() and would like to switch to the built-in version, one helpful commenter suggests replacing your custom version with a wrapper that just calls array_replace_recursive(). There are also a few pure-PHP implementations of array_replace_recursive() if you’re stuck with an older version of PHP.