Article

The PHP Anthology Volume 1, Chapter 2 - Object Oriented PHP

Page: 1 2 3 4 5 6 7 8 9 10 11 Next

Understanding Scope

Write more than a few hundred lines of procedural PHP code and, no doubt, you’ll run into a parser error or, worse still, a mysterious bug caused by your accidentally having used a function or variable name more than once. When you’re including numerous files and your code grows increasingly complex, you may find yourself becoming more paranoid about this issue. How do you stop such naming conflicts from occurring? One approach that can help solve this problem is to take advantage of scope to hide variables and functions from code that doesn’t need them.

A scope is a context within which the variables or functions you define are isolated from other scopes. PHP has three available scopes: the global scope, the function scope, and the class scope. Functions and variables defined in any of these scopes are hidden from any other scope. The function and class scopes are local scopes, meaning that function X’s scope is hidden from function Y’s scope, and vice versa.

The big advantage of classes is that they let you define variables and the functions that use them together in one place, while keeping the functions hidden from unrelated code. This highlights one of the key theoretical points about the object oriented paradigm. The procedural paradigm places most emphasis on functions, variables being treated as little more than a place to store data between function calls. The object oriented paradigm shifts the emphasis to variables; the functions “back” the variables and are used to access or modify them.

Let’s explore this through an example:

<?php    
// A global variable    
$myVariable = 'Going global';    
   
// A function declared in the global scope    
function myFunction()    
{    
 // A variable in function scope    
 $myVariable = 'Very functional';    
}    
   
// A class declared in the global scope    
class MyClass {    
 // A variable declared in the class scope    
 var $myVariable = 'A class act';    
   
 // A function declared in the class scope    
 function myFunction()    
 {    
   // A variable in the function (method) scope    
   $myVariable = 'Methodical';    
 }    
}    
?>

In the above example, each of the $myVariable declarations is actually a separate variable. They can live together happily without interfering with each other, as each resides in a separate scope. Similarly, the two myFunction declarations are two separate functions, which exist in separate scopes. Thus PHP will keep all of their values separate for you.

Scope becomes important when you start to use object oriented programming in a significant way in your PHP applications. As many classes can have methods of the same name, you can design separate classes to deliver the same application programming interface (API). The scripts that use the classes can then use the same method calls, irrespective of which class was used to instantiate the object they’re working with. This can be a very powerful technique in writing maintainable code. We’ll look at this point more when we discuss polymorphism later in this chapter.

A Three Liner

Here’s how we could make the class even easier to use:

Example 2.6. 4.php (excerpt)

<?php    
// Page class    
class Page {    
   
 // Declare a class member variable    
 var $page;    
 var $title;    
 var $year;    
 var $copyright;    
   
 // The constructor function    
 function Page($title, $year, $copyright)    
 {    
   // Assign values to member variables    
   $this->page = '';    
   $this->title = $title;    
   $this->year = $year;    
   $this->copyright = $copyright;    
   
   // Call the addHeader() method    
   $this->addHeader();    
 }    
   
 // Generates the top of the page    
 function addHeader()    
 {    
   $this->page .= <<<EOD    
<html>    
<head>    
<title>$this->title</title>    
</head>    
<body>    
<h1 align="center">$this->title</h1>    
EOD;    
 }    
   
 // Adds some more text to the page    
 function addContent($content)    
 {    
   $this->page .= $content;    
 }    
   
 // Generates the bottom of the page    
 function addFooter()    
 {    
   $this->page .= <<<EOD    
<div align="center">&copy; $this->year $this->copyright</div>    
</body>    
</html>    
EOD;    
 }    
   
 // Gets the contents of the page    
 function get()    
 {    
   // Keep a copy of $page with no footer    
   $temp = $this->page;    
   
   // Call the addFooter() method    
   $this->addFooter();    
   
   // Restore $page for the next call to get    
   $page = $this->page;    
   $this->page = $temp;    
   
   return $page;    
 }    
}

This time, we’ve modified the constructor to accept all the variables needed for both the header and the footer of the page. Once the values are assigned to the object’s member variables, the constructor calls the addHeader method, which builds the header of the page automatically:

 // The constructor function    
 function Page($title, $year, $copyright)    
 {    
   // Assign values to member variables    
   $this->page = '';    
   $this->title = $title;    
   $this->year = $year;    
   $this->copyright = $copyright;    
   
   // Call the addHeader() method    
   $this->addHeader();    
 }

As you can see, like member variables, methods can be called with the $this variable.

The addHeader method itself now fetches the data it needs from the member variables. For example:

<title>$this->title</title>

We’ve also updated the get method so that it calls the addFooter method before returning the contents of the $page member variable. This means that when we come to fetch the finished page, the footer is added automatically.

 // Gets the contents of the page    
 function get()    
 {    
   // Keep a copy of $page with no footer    
   $temp = $this->page;    
   
   // Call the addFooter() method    
   $this->addFooter();    
   
   // Restore $page for the next call to get    
   $page = $this->page;    
   $this->page = $temp;    
   
   return $page;    
 }

It took a little work to make sure we could call get more than once, without adding extra footers to the page, but this complexity is neatly hidden within the class.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links