In PHP, I like to think each function has its own Dictionary/Hash to manage its scope and that code outside of functions is actually part of a “Main” function. I think of it as a dictionary because through implicit evaluation, you can create variables with spaces and other reasons you’ll see at the conclusion of this article. Those are the only two data types which effectively connate that ability. But that means that whenever a new variable is instantiated, it is simply recorded in the dictionary. How variables get managed within the dictionary is non-consquencial to us. As PHP’s virtual machine consumes a function block, it creates the dictionary. It then adds, modifies and removes variables according to programmer-specified code. As the function hits the final closing brace, the VM iterates across the dictionary freeing memory.
Of course, there are there are two special cases to this. The first would be PHP’s global
keyword. Any variable marked as global causes the variable to refer to the Main-level (global-level) dictionary. It is similar to a reference, but has subtle differences which I’ll explain in a momeny. The second is references.
In PHP4, variables default to being passed-by-value. That means that when $result = square ($bignum);
is called, the value of $bignum
is copied into the function square’s dictionary. This means within square, that parameter refers to a separate variable which has the same value as the variable passed to square
. Under this case, the separate variable plays by the initialize-use-free rules already established. There is also a possibility to pass-by-reference. This gives a function the ability to update passed parameters. Under this case, the function using the variable should not free the variable at the end of the function. It still needs to be entered into the dictionary, but likely has a special flag to suppress freeing the variable when it would otherwise fall out of scope, as well as some kind of instruction to defer to another variable for retrieving or storing a value.
A second special case on references are when a function returns an reference to a variable it created. While there are performance advantages to doing this compared to returning a variable directly, I chose to think of this as putting a variable in the caller’s dictionary and within the function, treating it as a reference. This is not what actually happens, but without getting into a discussion on reference counting, is the easiest way of thinking about it.
In most C-style languages, variables are initiated within a pair of curly braces. In PHP, no matter how many curly braces exist in a function, the variable only belongs within the function-level pair. Therefore, included files can operate on the same scope as the code surrounding it. And references are just special variables which are used but not managed by a function.
PHP4 and 5 are largely the same on this topic. PHP5 defaults to pass-by-reference and many keywords consume and offer references by default, which does complicate understanding where a variable actually exists and when it is no longer available, but still ultimately plays by these rules.
Now that you understand roughly how PHP’s VM handles references, let’s return to global variables. In most languages, a variable marked global automatically shows up in each nested function’s dictionary. In PHP, it only populates when explicitly instructed. But the garbage collection difference is that you can create a reference to a variable which does not exist. global $figTree;
instructs the top-level dictionary’s $figTree
variable to be available within the particular function. But, it does not create $figTree
if it does not exist. If $figTree
does exist, than it is treated like a reference and normal reference rules apply. But if it does not exist, it’s like a reference to a place holder. Normal rules apply, but merely coding global $figTree
when it is the only place that refers to it actually fails to create a variable. Its not a normal variable which falls out of scope with the ending of the function, its a reference to a variable which fails to exist (yet). Often, this could be considered a Null Pointer. But PHP allows us to do things like
function x () {
global $a;
$b = y ($a);
}
function y (&$var) {
if (!$var) {
$var = 1;
} else {
++$var;
}
return $var;
}
do {
x();
} while (true);
We have passed a reference to a variable which does not exist to a function which takes its argument as a reference. This function gives the reference variable a value, which is persisted through x
’s repeated calls to global
. Y
has no idea that $var
does not actually exist. It merely assigns/changes $var
’s value and returns it.
You can see that global is clearly more complicated than it seems. Its further complicated (in use) by the fact that each function shares it. There is also a static
keyword which is more complicated still, but keeps the variable private to a function. I’ve never seen it used in any real-world code though.
Considering variables to be stored in a dictionary like this should make some other concepts more obvious in implementation, though. The dollar sign is simply a delimiter to PHP’s VM to look up a variable in its dictionary. Therefore, two dollar signs just means to pass the dictionary element’s value to another lookup call. Consider:
$red = "#ff0000";
$color = "red";
echo $$color;
In the dictionary, there are records red and color. The first line establishes “red”, the second, “color”. On the third, $$color is interpreted as $ $color. This would therefore be $ “red” or more simply, $red. This works because actual reference establishing is deferred until after looking up variable’s values. Likewise,
$colorname = "midnight blue";
$$colorname = "#000020";
//there is now a variable called "midnight blue" in this namespace
Which allows us to establish a variable containing a space, but still plays by simple rules. Likewise, one of PHP’s magic functions which could never be written in PHP is explained: get_defined_vars. All get_defined_vars does is cast its internal dictionary to a PHP name-value hash.
While this article has expanded beyond just explaining how PHP offers garbage collection, hopefully now, garbage collection, some aspects of implicit evaluation and even functions like get_defined_vars
are now all clearer than before. As always, ask me questions if you don’t understand any part of it.
No comments:
Post a Comment