Friday 9 April 2010

PHP benchmarks (part 2)

Let's continue ...

Next test is:

Test
Is it worth the effort to calculate the length of the loop in advance?
E.g. "$size=count($array); for ($i=0; $i<$size; $i++)" instead of "for ($i=0; $i<count($array);$i++)"

This test is good in terms of optimization (precalculation of array's size is worth, because size of an array is being calculated every time at new iteration), but one thing has to be mentioned here, assumption is that array doesn't change in terms of adding or deleting items, because "count" would be different from $size and these two loops would do different things. So, you should be aware of what you're doing because you could get unexpected results.


Test
$obj = new SomeClass()    vs.    $obj =& new SomeClass() using the =&-ref-operator

 You should be careful with this, because they are not identical. I'll show you in one example:

class A {
public $p = 1;
}

$a = new A;
$b = $a;
$c = & $a;

echo $a->p . '<br>';

$b->p++;

echo $a->p . '<br>';

$c->p++;

echo $a->p . '<br>';


echo '<br>##############<br>';

echo '<br>$a = NULL;<br>';

$a = new A;
$b = $a;
$c = & $a;


$a = NULL;

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

echo '<br>##############<br>';

echo '<br>$b = NULL;<br>';

$a = new A;
$b = $a;
$c = & $a;

$b = NULL;

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

echo '<br>##############<br>';

echo '<br>$c = NULL;<br>';

$a = new A;
$b = $a;
$c = & $a;

$c = NULL;


var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';


And the results are:


1
2
3

##############

$a = NULL;
NULL
object(A)#2 (1) { ["p"]=> int(1) }
NULL

##############

$b = NULL;
object(A)#1 (1) { ["p"]=> int(1) }
NULL
object(A)#1 (1) { ["p"]=> int(1) }

##############

$c = NULL;
NULL
object(A)#2 (1) { ["p"]=> int(1) }
NULL

As you can see, variable's reference acts as described in my previous post - as variable alias (one more name). As for object, object's reference is just an identifier of particular object. There can be multiple identifiers, just like references, but difference is that references are closely bonded to variable and object's reference to object's identifier. Here is small graphic illustration:

$a = $c => $obj
$b => $obj

Here is one more example to illustrate that, I'll use "unset" to show the difference (and to show difference between "$a = NULL" and "unset($a)"):

echo '<br>##############<br>';

echo '<br>unset $a<br>';

$a = new A;
$b = $a;
$c = & $a;


unset($a);

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

echo '<br>##############<br>';

echo '<br>unset $b<br>';

$a = new A;
$b = $a;
$c = & $a;

unset($b);

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

echo '<br>##############<br>';

echo '<br>unset $c<br>';

$a = new A;
$b = $a;
$c = & $a;

unset($c);

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

 And the results are:


##############

unset $a
NULL
object(A)#1 (1) { ["p"]=> int(1) }
object(A)#1 (1) { ["p"]=> int(1) }

##############

unset $b
object(A)#2 (1) { ["p"]=> int(1) }
NULL
object(A)#2 (1) { ["p"]=> int(1) }

##############

unset $c
object(A)#1 (1) { ["p"]=> int(1) }
object(A)#1 (1) { ["p"]=> int(1) }
NULL

Now, let's go back to previous example and see what happens when setting variables to "NULL".
Here are results once more:

##############

$a = NULL;
NULL
object(A)#2 (1) { ["p"]=> int(1) }
NULL

##############

$b = NULL;
object(A)#1 (1) { ["p"]=> int(1) }
NULL
object(A)#1 (1) { ["p"]=> int(1) }

##############

$c = NULL;
NULL
object(A)#2 (1) { ["p"]=> int(1) }
NULL

So...


$a = $c => $obj
$b => $obj

$c = NULL

$a = $c => NULL 
$b => $obj

unset($c)


$a => $obj
$b => $obj



You can draw other situations for practice. :)


When I first observed how "unset($a)" and "$a = NULL" work, it seemed to me that they behave in identical way:


$a = 'Test';
unset($a);
var_dump($a);

This produces "NULL", so I thought "$a = NULL" would produce same result. But they behave different in the background. I haven't looked at PHP's internals, but I suppose "unset" deletes variable from symbol table, while setting to "NULL" doesn't delete variable from symbol table, it just setts it's value to "NULL". This can be illustrated by next example:

$a = 'Test';

echo '<pre>';
print_r(get_defined_vars());
echo '</pre>';


echo '<br>Unset $a<br>';
unset($a);

echo '<pre>';
print_r(get_defined_vars());
echo '</pre>';


echo '<br>$a = NULL<br>';

$a = 'Test';

$a = NULL;

echo '<pre>';
print_r(get_defined_vars());
echo '</pre>';

And result is:

Array
(
    [GLOBALS] => Array
        (
            [GLOBALS] => Array
 *RECURSION*
            [_POST] => Array
                (
                )

            [_GET] => Array
                (
                )

            [_COOKIE] => Array
                (
                )

            [_FILES] => Array
                (
                )

            [a] => Test
        )

    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

    [a] => Test
)

Unset $a
Array
(
    [GLOBALS] => Array
        (
            [GLOBALS] => Array
 *RECURSION*
            [_POST] => Array
                (
                )

            [_GET] => Array
                (
                )

            [_COOKIE] => Array
                (
                )

            [_FILES] => Array
                (
                )

        )

    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

)

$a = NULL
Array
(
    [GLOBALS] => Array
        (
            [GLOBALS] => Array
 *RECURSION*
            [_POST] => Array
                (
                )

            [_GET] => Array
                (
                )

            [_COOKIE] => Array
                (
                )

            [_FILES] => Array
                (
                )

            [a] => 
        )

    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

    [a] =>  
) 

Be careful when using "isset". From PHP documentation (http://www.php.net/manual/en/function.isset.php):

Determine if a variable is set and is not NULL.

This means - is defined in symbol table and it's value is not NULL. There is a difference between this two conditions in terms of producing a notice as we can see here:

echo $a;
$a = NULL;
echo $a;

First "echo" produces notice, while second one does not (because there is no $a variable in symbol table - it is not defined as notice says).


That's all for this time, more info coming!

No comments:

Post a Comment