PHP Scoping

Chapter 11 19 mins

Learning outcomes:

  1. What is a scope
  2. Variables with a global scope
  3. Variables with a local scope
  4. The global keyword
  5. Variable resolution in PHP

Introduction

Working with variables is fundamental to almost all programming languages including PHP. And a fundamental idea to variables is that of variable scopes — i.e. where is a variable accessible.

Understand the concept of a variable's scope is crucial to working fluidly with variables and countless preventing errors from creeping into our programs.

Whether we know it or not, each of our programs essentially uses scopes in some way, and hence they are one of those ideas which if not learned properly will lead to confusions in the future when understanding other ideas and building complicated programs.

So let's begin.

What are scopes?

Let's first start by unraveling the true meaning of the term 'scope'.

A scope is a characteristic of a variable that defines exactly where is the variable accessible.

The first part of this definition clearly specifies that scope is not a standalone entity — it's a characteristic tied of a variable (or more generally, to an identifier).

Secondly, the scope of a given variable describes the places where that variable is accessible.

For instance, the scope is what answers questions such as is this variable accessible outside this block statement; is this variable accessible outside this function; does this variable assignment modify a local variable; and so on.

Right now, this definition might still seem vague and unclear, but as we'll progress through this chapter everything will become clear.

As far as PHP is concerned, it defines two scopes:

  1. Global scope
  2. Local scope

A variable with a global scope is accessible everywhere in the whole PHP program. A variable with a local scope is accessible only within the function where it's defined.

Let's explore both of these scopes in more detail...

Global scope

Uptil this point in this course, most of the variables that we created were global variables i.e. variables with a global scope.

So what is so special about the global scope?

Well, let's see:

A variable with a global scope is accessible throughout the whole program.

The word 'global' means 'relating to the whole of something' and that's exactly what it means in the term 'global scope' i.e. the underlying variable is available throughout the whole program.

A variable with a global scope is also referred to as a globally-scoped variable, or simply as a global variable.

As we shall see later on in this chapter, a global variable is not accessible by default inside a function, but we can signal PHP to do so with the help of a keyword. In that sense, clearly a global variable is capable of being accessed everywhere in a program.

For instance, consider the code below:

<?php

$x = 10;

if (true) {
   $greeting = 'Hello World!';
}

Here, we've defined the variable $x directly inside the PHP program and not inside a function, hence it's a global variable.

Same goes with the variable $greeting — it's defined inside the if statement, yet it's still global because it's not inside a function.

Note one thing with $greeting here — only if the if body executes does the variable $greeting come into existence. In other words, if the condition of if isn't met, and consequently its body isn't executed, the variable won't be created.

However in the code below, $x is not global for an obvious reason:

<?php

function f() {
   $x = 10;
}

f();

$x is defined inside the function f(), likewise it's not a global variable.

If we try to access $x outside the function, we'll get an undefined variable warning, as shown below:

<?php

function f() {
   $x = 10;
}

f();

var_dump($x);
Warning: Undefined variable $x in <path> on line 9

Simple.

Now one thing that might be obvious, but still worth mentioning, is that although a global variable is accessible everywhere in a program, this only applies after it has been defined. That is, before the definition of a global variable, it is NOT accessible.

Consider the code below:

<?php

var_dump($x);

$x = 10;

var_dump($x);
Warning: Undefined variable $x in <path> on line 3 NULL int(10)

In line 3, as we try to access $x before its definition in line 5, PHP raises a warning. This illustrates the fact that accessing a variable before its definition is not possible and will just lead to warnings.

Here's a quick test for you.

What does the following code output?

<?php

for ($i = 0; $i < 3; $i++) {
   $a = 0;
}

var_dump(isset($i));
var_dump(isset($a));
  • bool(true) bool(true)
  • bool(true) bool(false)
  • bool(false) bool(true)
  • bool(false) bool(false)
Both the variables $i and $a are global variables, and are hence available right after their definitions. This means that both the isset() calls return true. This goes with choice (A).

Local scope

When a variable is defined inside a function, it has a local scope. That is, it's only accessible within the bounds of the function — not anywhere else.

So stating it formally:

A variable with a local scope is accessible only within the function where it's defined — not outside it.

This definition also describes how to know whether a variable has a local scope. That is, any variable that's defined inside a function has a local scope.

When a variable is defined inside a function, it remains in memory only uptil the lifetime of the function. Once the function completes and thereby exits, the variable is deleted.

A variable with a local scope is also known as a locally-scoped variable, or simply as a local variable.

Time for an example:

<?php

function f() {
   $x = 10;
   var_dump($x);
}

function g() {
   $y = 20;
   var_dump($y);
}

f();
g();

Here, we've defined the variable $x inside the function f(). Hence, $x is a local variable that's just limited to the function f(). Same goes with the variable $y which is defined in the function g()$y is local to g().

Running this code gives us the following output:

int(10) int(20)

So far, so good.

If we try to access either variable from the other function, we'll get a warning.

For instance, in the code below, we access $x inside g() and because $x doesn't exist inside g(), PHP signals a warning:

<?php

function f() {
   $x = 10;
   var_dump($x);
}

function g() {
   $y = 20;
   var_dump($y);
var_dump($x); } f(); g();
int(10) int(20) Warning: Undefined variable $x in <path> on line 11 NULL

Simple idea, isn't this?

Moving on, as far as the parameters of a function are concerned, they are merely local variables of the function (created by the engine automatically when entering into the function). Hence, parameters are also local to a function.

And this means that we could have multiple functions with the same parameter names — they won't conflict with one another.

An example follows:

<?php

function add($x, $y) {
   return $x + $y;
}

function multiply($x, $y) {
   return $x + $y;
}

Here we have two functions sum() and multiply() with the same parameter names $x and $y. The functions along with their parameter names operate entirely separately — one doesn't know about the other.

This is a highly useful feature of modern-day programming languages.

That is, variables (obviously including parameters) defined inside functions disappear once the function exits and hence don't conflict with similarly-named variables in other functions. Not does this only save memory but also allows us to use the same names in multiple functions leading to more consistent naming and readable code.

Imagine we had to do the following to create four different functions performing the basic arithmetic operations:

<?php

function add($x, $y) {
   return $x + $y;
}

function subtract($x2, $y2) {
   return $x2 - $y2;
}

function multiply($x3, $y3) {
   return $x3 * $y3;
}

function divide($x4, $y4) {
   return $x4 / $y4;
}

We are creating new names for each set of parameters. This is clearly undesirable and unreadable. Ideally, each set of parameters should just be $x and a $y.

To add to the confusion, imagine if these parameters become global once the underlying function is called — in that case, we can't use $x, $y, $x2, $y2, ..., and $y4 in our global code since they might override global variables with the same name leading to yet more problems.

So hopefully, it's now clear as to what could happen if we don't have local variables in programming — a complete coding catastrophe!

The global keyword

Recall from the section above that a global variable is accessible everywhere in a PHP program right after the point it's defined. This definition is completely alright, but just a little bit incomplete.

Specifically, when we're inside a function, the story is a little bit different.

First let's witness the different story in the code below:

<?php

$x = 10;
var_dump($x);

function f() {
   var_dump($x);
}

f();
int(10) Warning: Undefined variable $x in <path> on line 7 NULL

As is evident, it seems that the global variable $x isn't available in the function f().

Seems strange.

Let's decipher the exact issue.

In PHP, a global variable isn't made accessible inside a function, by default. The reason to why is this the case is entirely a design decision of the language.

Fortunately, to preserve the true global nature of a global variable i.e. of being accessible everywhere, PHP provides us with a keyword to signal to it that we want to use a particular global variable inside a function.

That keyword is global.

The global keyword goes inside a function's body, and signals to PHP to use a particular set of global variables inside the function.

Typically, global is the first statement inside a function where a global variable is required, but that's not mandatory.

Here's the general syntax:

function function_name(parameters) {
   global $var_1, $var_2, ..., $var_n;

   statements;
}

The global keyword is followed by the variable to use from the global context. Multiple variables are simply separated by a comma (,).

The global keyword can only appear inside a function.

Time to see global in action.

In the code below, we have the same setup as before, just this time the function f() has a global statement in it to call on to the variable $x from the global context:

<?php

$x = 10;
var_dump($x);

function f() {
   global $x;
   var_dump($x);
}

f();
int(10) int(10)

Because of the statement global $x here in line 7, PHP realizes that $x inside f() refers to the global variable $x and hence any assignments to $x apply to the global $x.

Simple.

Note that if the variable referred to in the global statement does not exist, it is created.

This can be seen as follows:

<?php

function f() {
   global $x;
   var_dump($x);
}

f();

var_dump($x);
NULL NULL

As can be seen here, no warning is raised even though $x isn't defined in the global context directly. This illustrates the fact that the global $x statement in line 4 creates the variable.

Simple, yet again.

Variable resolution

Whenever PHP encounters a variable, it has to resolve that variable — i.e. use its value in the expression or raise a warning if the variable doesn't exist.

This requires a careful approach for the engine to take. In this section, we aim to decipher exactly how a variable is resolved in PHP:

By far, variable resolution in PHP is simpler than in many other programming languages such as C++, JavaScript, Python and so on.

That is,

When PHP comes across a variable, it searches for that variable in the exact same context where the variable is referred to. If nothing is found there, a warning is raised for referring to a non-existent variable.

And that's it!

PHP's variable resolution vs. that of other languages

If you're familiar with Python or JavaScript, or even C, or C++, this model might sound quite simple. And the reality is that it really is simple.

There is no context traversals involved, as in Python, i.e. first searching for the variable in the local context, then in the outer context, then in the second outer context, and so on until the list of contexts gets exhausted, at which point an error is raised.

In PHP, a variable's access is resolved by looking right into the context where access was made — if the variable is there in the context, well and good; however if it ain't there, a warning ought to be raised.

Let's put this theory to real action:

In the code below, we refer to two variables in the global context i.e $x and $y.

<?php

$x = 10;
var_dump($x);

var_dump($y);

When PHP encounters $x in line 4, it starts the search for $x in the global context (since that's where $x is referred to). Because a match is found, the corresponding value is used in place of $x in the statement.

So far, so good.

However when it encounters $y in line 6, and performs the search for it in the global context, no match is found. Consequently, the statement in line 6 leads to a warning which we're quite familiar with by now:

int(10) PHP Warning: Undefined variable $y in <path> on line 6 on line 6 NULL

Let's move on to another example.

In the code below, we have a function f() where we refer to two variables $x and $y.

<?php

function f() {
   $x = 10;
   var_dump($x);

   var_dump($y);
}

f();

As before, when $x is encountered in line 5, the engine starts the search for $x in the local context of f(). Since a match is found, the corresponding value is used to resolve $x.

Moving on, when $y is encountered in line 7, the same process is repeated. This time, since there is no local variable $y in f(), a warning is raised:

int(10) Warning: Undefined variable $y in <path> on line 7 NULL

Very simple, yet again.

PHP simplifies variable resolution to a great extent.

Now this leads to one very good question which might've popped up in your mind as well:

When we use the global keyword to signal to the engine that we want to use a particular variable, and then when we actually refer to the variable inside the function, isn't this an instance where PHP doesn't search for the variable only in the local context of the function?

Well, no.

At the core, the global keyword operates a little bit differently than how it seems to.

We'll explore global in detail in the next chapter where we study references in PHP.

In particular, global creates a local variable that is simply a reference to a global variable with the same name — it doesn't literally call on to the global variable from the global context. Hence, when we refer to the variable in the function, PHP is still searching for the variable in the local context.

This is a bit tedious concept to wrap the mind around, and likewise we'll slowly and gradually unravel it in the next chapter.