Using func_get_args() as second (or more) parameter

Permanent Link: Using func_get_args() as second (or more) parameter 29. April 2009 Comment No Comment

There's a strange bug in PHP we recently came across: When using func_get_args() is used as second (or third or fourth etc) parameter, PHP crashes with a Fatal Error.

Try this code:

function returnSomething()
{
        return func_get_args();
}

function callSomeFunction($message)
{
        someFunction(func_get_args(), 'Hello World');
        someFunction(1, returnSomething());
        someFunction(1, func_get_args());
}

function someFunction($code, $message)
{
        print($message . PHP_EOL);
}

callSomeFunction('Hello World');

The result should be

Hello World
Array
Array

yet you get

Hello World
Array

Fatal error: func_get_args(): Can't be used as a function parameter
in /home/dominik/test.php on line 12

The code works with any other function (see example code), only func_get_args() causes a crash.

So I thought: Let's commit a bug! I then found out that this very bug has already been committed in 2005: http://bugs.php.net/bug.php?id=27887. The bug was closed (unfixed) with this really unsatisfactory explanation:

[16 Jun 2005 1:34am UTC] tony2001@php.net
Damien, the docs say: "This function cannot be used directly as a function
parameter. Instead, its result may be assigned to a variable, which can
then be passed to the function.", so don't use it as a parameter.

[16 Jun 2005 9:04am UTC] derick@php.net

So there is no bug, and the docs already describe it -> bogus.

Of course: Why should I fix a bug, when I can just put a note in the documentation that says "don't use it as parameter".

Edit: I filed a bug and it was closed with the comment "This is a known issue and have been fixed in 5.3.". Good to know!

MySQL server has gone away

Permanent Link: MySQL server has gone away 1. April 2009 Comment No Comment

Today we had a database crisis due to a powercut. Apart from corrupted tables (because of the immediate "shutdown") we also had another problem: CLI scripts/cronjobs suddenly threw a MySQL server has gone away Exception after a really short amount of time (maybe 30 seconds)

I found this useful list, the only problem was: all the points didn't match for my case. So we came up with an own list that we worked through:

  • Flush privileges
  • Restore the User grants/privileges
  • Restart the MySQL server
  • dpkg-reconfigure mysql-server-5.0 (or similar)

In our case restarting the MySQL server fixed the problem.

Using array_unique() with multidimensional arrays

Permanent Link: Using array_unique() with multidimensional arrays 31. Januar 2009 Comment Comments (2)

There's one problem with array_unique(): It doesn't work with multidimensional arrays. Here's an example:

$array = array(
array(
'id' => 123,
'name' => 'Some Product',
'ean' => '1234567890123'
),
array(
'id' => 123,
'name' => 'Some Product',
'ean' => '4852950174938'
),
array(
'id' => 123,
'name' => 'Some Product',
'ean' => '1234567890123'
),
);
$uniqueArray = array_unique($array);
var_dump($uniqueArray);

Two elements are exactly the same, but one element has a different EAN, yet the var_dump() returns the following:

array(1) {
[0]=>
array(3) {
["id"]=>
int(123)
["name"]=>
string(12) "Some Product"
["ean"]=>
string(13) "1234567890123"
}
}

Obviously this is unexpected behaviour. array_unique() threw out the second element, which is clearly not the same as Element 1 and 3. The easiest way I came across is using md5 hashes for comparison of the elements. All you need is to iterate over the first dimension, serialize it and create a MD5 hash of it for comparison:

/**
* Create Unique Arrays using an md5 hash
*
* @param array $array
* @return array
*/
function arrayUnique($array, $preserveKeys = false)
{
// Unique Array for return
$arrayRewrite = array();
// Array with the md5 hashes
$arrayHashes = array();
foreach($array as $key => $item) {
// Serialize the current element and create a md5 hash
$hash = md5(serialize($item));
// If the md5 didn't come up yet, add the element to
// to arrayRewrite, otherwise drop it
if (!isset($arrayHashes[$hash])) {
// Save the current element hash
$arrayHashes[$hash] = $hash;
// Add element to the unique Array
if ($preserveKeys) {
$arrayRewrite[$key] = $item;
} else {
$arrayRewrite[] = $item;
}
}
}
return $arrayRewrite;
}

$uniqueArray = arrayUnique($array);
var_dump($uniqueArray);

Now the result is the one array_unique() should have already given:

array(2) {
[0]=>
array(3) {
["id"]=>
int(123)
["name"]=>
string(12) "Some Product"
["ean"]=>
string(13) "1234567890123"
}
[1]=>
array(3) {
["id"]=>
int(123)
["name"]=>
string(12) "Some Product"
["ean"]=>
string(13) "4852950174938"
}
}

This works with as many dimensions as you like.