Pre-declare all private/local variables?

Since you’re talking about private, protected and public I take it you’re talking about properties, instead of variables.
In that case: yes, you should declare them beforehand.

Because of how PHP objects are designed, an array (properties_table) is created on compile time. This array ensures that accessing a given property is as fast as possible. However, if you add properties as you go along, PHP needs to keep track of this, too. For that reason, an object has a simple properties table, too.
Whereas the first (properties_table) is an array of pointers, the latter is a simple key => value table.
So what? Well, because the properties_table contains only pointers (which are of a fixed size), they’re stored in a simple array, and the pointers are fetched using their respective offsets. The offsets are stored in yet another HashTable, which is the ce->properties_info pointer.

As bwoebi pointed out to me in the comments: getting the offset (HashTable lookup) is a worst-case linear operation (O(n)) and predefined property lookups are constant-time complex operations (O(1)). Dynamic properties, on the other hand need another HashTable lookup, a worst-case linear operation (O(n)). Which means that, accessing a dynamic property takes in average about twice as long. Authors of the Wikipedia can explain Time-Complexity far better than I can, though.

At first, access modifiers might seem irrelevant. As you go along, you’ll soon find that sometimes, you just don’t want to take the chance that some property of some object gets modified by some bit of code. That’s when you see the value of private.
If an object contains another object, that holds all sorts of settings that your code will rely upon, for example, you’ll probably use a getter method to access those settings from the outside, but you’ll leave that actual property tucked away nicely using private.

If, further down the line, you’re going to add data models and a service layer to your project, there’s a good change you’ll write an (abstract) parent class, if only for type-hinting.
If those service instances contain something like a config property, you’ll probably define that getter in the parent class (to only define it once). private means that only the current class has access to a property, but since you’re not going to have an instance of the parent to work with, but an instance of the child, you’ll see why protected is invaluable when dealing with larger projects, too.

As far as temporary variables are concerned, be it in methods, functions or anywhere else, you don’t have to predeclare them, except for, in certain cases arrays:

public function foo()
{
    $temp = $this->getSomeValue();
    return $temp ? $temp +1 : null;
}

Is perfectly valid, and wouldn’t work any better if you were to write

public function foo()
{
    $temp;// or $temp = null;
    $temp = $this->getSomeValue();
    return $temp ? $temp +1 : null;
}

However, it’s not uncommon to see simething like this:

public function bar($length = 1)
{
    for ($i=0;$i<$length;$i++)
    {
        $return[] = rand($i+1, $length*10);
    }
    return $return;
}

This code relies on PHP being kind enough to create an array, and assign it to $return when the $return[] = rand(); statement is reached. PHP will do so, but setting your ini to E_STRICT | E_ALL will reveal that it doesn’t do so without complaining about it. When passing 0 to the method, the array won’t be created, and PHP will also complain when it reaches the return $return; statement: undeclared variable. Not only is it messy, it’s also slowing you down! You’re better off declaring $return as an array at the top of the scope:

public function bar($length = 1)
{
    $return = array();//that's it
    for ($i=0;$i<$length;$i++)
    {
        $return[] = rand($i+1, $length*10);
    }
    return $return;
}

To be on the safe side, I’d also check the argument type:

/**
 * construct an array with random values
 * @param int $length = 1
 * @return array
 **/
public function bar($length = 1)
{
    $length = (int) ((int) $length > 0 ? $length : 1);//make length > 0
    $return = array();
    for ($i=0;$i<$length;$i++)
    {
        $return[] = rand($i+1, $length*10);
    }
    return $return;
}

Leave a Comment