Because OOP helps structure PHP programs into practical modules for re-use and change, the ability of each module to communicate with another module or set of modules is key to creating a successful OOP program. For example, your client class that makes requests must have some way of communicating with the target of its request. To instantiate an instance of a class when making a request, the new statement creates an object (instance) of that class. (That’s one reason constructor functions are all set to public by design. Even if you do not include a constructor function in a class one is automatically included.)
However, you do not want every object communicating with every other object in an OOP application. Consider, for example, a Web design and development company. You may not want your programmers sending directives to your design or UX people. (e.g., Let’s put an animated PacMan on every page.) or your design people telling your programmers what to do (e.g. The colors of your source code listings are all wrong. Change them to pastels.) However, you do want the head of your development team to communicate with the head of your design team to coordinate design and development. It’s the same with OOP programs; you want to organize the flow of communication between objects to avoid tangles and unexpected consequences.
A Double Feature
This will be a two-part post because those videos can get long quick! Here’s Part I on Visibility:
To find out a little more about visibility, this next video shows some OOP programs using different types of visibility and how they can be accessed.
It will probably help if you take a minute and download the example files. You should be able to put the programs in your favorite IDE and watch the video. That’ll probably give you a clear idea of how visibility works in different contexts.
If you have any feedback about the videos or blog, please feel free to use the comments. Like to hear from you.
Earlier this summer I completed a course through Rice University on Python. It was an introduction to making games with Python, and the four professors who taught it, did so brilliantly. One of the nagging issues that came up early was the use of global variables. In a clear explanation of the difference between local and global variables, virtually identical to PHP, we went through several game development exercises. At the very end of the class, however, we were admonished not to use global variables.
Online, you will find plenty of reasons to avoid globals in every computer language, but the main reason is one of maintainability. Because globals are accessible to all functions, their state can be changed by all functions. As a result, you may get unexpected outcomes that can be very difficult to track down, especially in larger programs. It’s like having a wild hare running through your program.
Encapsulation and Global Variables
Let’s start off with a simple example of global troubles. The following two programs represent sequential/procedural listings with a global.
$gvar="Hello everyone!";function showOff(){echo$GLOBALS['gvar'];}function fixUp(){$GLOBALS['gvar']="If it weren't for treats, dogs would rule the world.";}
fixUp();
showOff();?>
The ouput is wholly different for these two programs when the function showOff() is called:
Hello everyone!
If it weren’t for treats, dogs would rule the world.
As programs grow in size and complexity, the problem of globals grows proportionately. (If multiple programmers are involved, the problem grows exponentially!).
Now let’s look at the same issue in a class with a global variable.
class Alpha
{public$gvar="Hello everyone!";publicfunction __construct(){echo$GLOBALS['gvar'];}}$worker1=new Alpha();
It throws an error:
Notice: Undefined index: gvar in ….
Rather than trying to find a clever way to get globals into classes, using either the keyword global or the associative array $GLOBALS, let’s just say that a focus on visibility in classes will better serve further discussion of global scope when it comes to OOP encapsulation. (Visibility will be discussed in an upcoming post.)
Local Variables in Classes and Methods
Local variables work with methods in the same way as they do in unstructured functions. The locality of the variable does not matter in terms of return to a call or request. As with all other visibility, that depends on the method. The following example shows a local variable named $local in multiple methods with different content and different visibility. The Client class has a local variable in the constructor function, $runner. The following listing shows a request from within a class and by an external client.
ini_set("display_errors","1");ERROR_REPORTING(E_ALL|E_STRICT);class LocalReport
{publicfunction __construct(){echo$this->showOff1()." ";echo$this->showOff2()." ";}privatefunction showOff1(){$local="All good things come to pass.";return$local;}privatefunction showOff2(){$local="Fatal assumptions: He will change; she won't change.";return$local;}publicfunction showOff3(){$local="We serve the public (visibility)!";return$local;}}class Client
{publicfunction __construct(){$runner=new LocalReport();echo$runner->showOff3();}}$worker=new Client();?>
The output is:
All good things come to pass.
Fatal assumptions: He will change; she won’t change.
We serve the public (visibility)!
Whether to use local variables or class properties in OOP development depends on the purpose of the application under development. I tend to go for private properties to better insure encapsulation, but local variables can be handy in certain types of implementations. In either case, neither is subject to the problems associated with global variables. Superglobals
Superglobals in PHP are automatic predefined global variables available in all scopes throughout a script. Most PHP developers are familiar with $_GET and $_POST, but other superglobals such as $_COOKIE, $_SESSION and $_SERVER are commonly used as well. Elsewhere on this blog, injection attacks through superglobals have been discussed, but here I want to look at the relationship between OOP/Design Patterns and superglobals.
To get a good idea of the “superness” of superglobals, consider a typical OOP program where the requesting class is a client. It calls a class that uses a superglobal. Also, to acknowledge Brazil’s 2014 World Cup hosting, and the publication of Learning PHP Design Patterns in Portuguese (Padrões de Projeto em PHP), I thought I’d create the UI in Portuguese as shown in Figure 1:
Figure 1: Data input module
The HTML data entry is a simple one, asking for the user’s favorite team and favorite sport. They are saved in the super global elements, ‘team’ and ‘sport’ and then sent off using the post method. The following HTML code was used:
Dê entrada com o nome da equipe e do esporte em umas caixas de texto apropriadas:
You’ll have to excuse my poor Portuguese. In English it asks to enter your favorite team and sport. (As a long-suffering Chargers fan, you can see the sample entry in Figure 1.) Also, it needs some CSS, lest you think me a total savage:
The client class (SuperClient) is little more than a trigger to call a class to process the superglobals. However, the client has no superglobals itself. This is significant in that SuperClient.php is called by the HTML document (DataEntry.html).
class SuperGlobal
{private$favoriteTeam;private$favoriteSport;publicfunction __construct(){$this->favoriteTeam=$_POST['team'];$this->favoriteSport=$_POST['sport'];echo"Minha equipe favorita é $this->favoriteTeam. ";echo"Meu esporte favorito é $this->favoriteSport. ";}}?>
When you run the program, your output will look something like the following:
Minha equipe favorita é Chargers. Meu esporte favorito é football.
That shows that a superglobal can be accessed from even the most encapsulated environment. In the sense that the HTML Document called the SuperClient and yet the superglobals were available in the SuperGlobal object should tell you (and show you) that once launched from an HTML document a superglobal can be accessed from any PHP file communicating directly or indirectly with the originating HTML document.
Can Superglobals Cause Global Trouble?
For superglobals to be a problem, they need to change unexpectedly within a program.
So the first question, we need to ask is, Can superglobals be changed once they are sent from an HTML document?
We showed that superglobals can get inside an encapsulated object, but can they be changed or do they maintain the values set by the HTML document? The following is a test to find out. With a slight change to the SuperGlobal class and a couple more objects, we can find out.
Step 1: Change the SuperGlobal class to the following:
//Include new classinclude_once('GlobalChanger.php');class SuperGlobal
{private$favoriteTeam;private$favoriteSport;publicfunction __construct(){$this->favoriteTeam=$_POST['team'];$this->favoriteSport=$_POST['sport'];echo"Minha equipe favorita é $this->favoriteTeam. ";echo"Meu esporte favorito é $this->favoriteSport. ";//Add a new line$caller=new GlobalChanger();}}?>
Step 2: We need a class to change the values of the superglobals and call another object to display the changes in the same super global.
My friend Sudhir Kumar at PandaWeb.in from Chennai, India is a cricket fan; so I decided to use his favorite team and sport to replace whatever team and sport is entered.
class SuperChanged
{private$newTeam;private$newSport;publicfunction __construct(){$this->newTeam=$_POST['team'];$this->newSport=$_POST['sport'];echo" Now my favorite team is $this->newTeam. ";echo"And my very favorite sport is $this->newSport. ";}}?>
Starting with the same html document initially used, we can now see that indeed the superglobal values have been changed, and they are quite available throughout the program.
Minha equipe favorita é Chargers.
Meu esporte favorito é football.
Now my favorite team is Team India.
And my very favorite sport is cricket.
As you can see, the GlobalChanger object changed the original values. Furthermore, it is clear that we were using the same superglobal array in the SuperChanged class when the $_POST values were passed to private variables and displayed using the echo statement.
Obviously, a PHP programmer cannot simply drop superglobals. Further, even though we can change their values, that doesn’t mean we should change them or even have an occasion to do so. But, we need to be aware of the problems with global variables. After all, superglobals are global variables, even in an encapsulated environment.
Conclusion
Two important points need to be emphasized here:
Don’t use global variables.
Where you have to use superglobals, don’t change their values dynamically in PHP.
Like everything else in programming there are exceptions, but remember that globals, while having a purpose, often loose that purpose in OOP programs and structured design patterns. When using superglobals, keep in mind that they are true globals and they can be changed, but only if the developer assigns them different values after they’ve been assigned values in HTML. As true globals, they can cause the same kinds of problems that any other globals can. So treat them more like constants, and let their originally assigned values from the HTML form stay put.
All classes in all programming languages are made up of two fundamental elements, 1) Methods and 2) Properties. In this installation of learning OOP in PHP, I want to look at properties.
To understand properties in a PHP class, it’s important to understand (at this stage) that we’re dealing with variables. Variables inside of a class can act as properties of that class or properties of a method within a class. In OOP, we speak of visibility of variables/properties. You will find an earlier post on this blog that explains private variables in detail, and future posts delve into visibility in greater detail. For now variables in PHP (and virtually every other programming language) have two basic types:
local
global
Generally speaking any variable declared outside of a function in a sequential or procedural listing is global, and any variable declared inside of a function is local. The same is true to some extent in OOP programming, but variables (or properties) require a different sense. Take a look at the video, and you’ll see the basics of variables within classes.
The video touches on the most fundamental aspects of variables and properties. However, as every PHP programmer knows, there’s no substitute for some clear practical OOP PHP code. The following examples show several different aspects of creating and using variables and properties.
All of these examples use a Client->Request->Class model. The first is similar to the one in the video except it has a client make the request: Client 1
Client1
//Client1.phpinclude_once('OneProp.php');class Client1
{publicfunction __construct(){//$oneProp is a local variable$oneProp=new OneProp();echo$oneProp->showProperties();}}//$worker is a global variable in this program$worker=new Client1();?>
More Properties and a Little JavaScript inside PHP Class
This last example is a little more involved. One of the properties is assigned an entire Web page using heredoc. Two more properties serve as labels and instructions. Here we use a little JavaScript, and the JavaScript event handler (onClick) uses the this statement and property reference using a dot:
this.src
Because the JavaScript is part of a heredoc string in a PHP property ($this->document), PHP does not attempt to execute the JavaScript or find an error in its format. (In other words it doesn’t throw an error when this.src appears instead of $this->src is in the JavaScript listing.)
To run this, you’ll need to download the following two graphic files:
Put the two graphic files into the same directory as the classes you’ll be using. Notice how the three different properties in the ImageSwap class are employed. Also note that in the two Client classes, the $worker variable (not a property because it does not belong to a class) is assigned an object. To download the two graphic files, just right click to download them and then move them to the same directory (folder) with your ImageSwap.php file. In the next installment of OOP PHP, we’ll look at the visibility that properties and methods can have and how to use them.
In deciding which design pattern to apply to this CMS, two came to mind. Because PHP is creating a Web page, creational patterns appeared to be the most appropriate. Both the Factory Method and the Abstract Factory were considered. The Factory Method is the simplest of the two and it can be expanded, and so I settled on it. The Abstract Factory would be more appropriate if the main goal was to select different Web page styles. This CMS is to update and use data from a MySQL table. Since a lot of files make up this CMS, it’s probably a good idea to download them first:
To get started, take a look at Figure 1. In Part IV of this series you saw how to put data into and retrieve it from a database and use in a Web page. That is pretty much what has been done here except the request is through the Creator interface to insure loose coupling. The PageCreator implements the factoryMethod() method which creates a requested product specified by the Client. As a result the Client is only loosely bound to the concrete product it requests.
Figure 1: File Diagram for Factory Method CMS
When the concrete creator object (PageCreator) passes the request for the concrete Product object (PageProduct1()), it does so through the deliverWeb() method—the method implemented through the Product interface.
Multiple Inheritance (Sort of)
Some languages like Java and Python support multiple inheritance. Strictly speaking, PHP does not, but you will find workarounds and you can combine inheritance and implementation in a single child class. In the declaration of the PageProduct1 class, you can see how this is done:
include_once('UniversalConnect.php');include_once('Product.php');include_once('ProductTools.php');class PageProduct1 extends ProductTools implements Product
{function deliverWeb(){$this->tableMaster="blogette";$this->hookup=UniversalConnect::doConnect();$this->loadContent();$this->content=array("css"=>$this->css,"title"=>$this->title,"header1"=>$this->header1,"header2"=>$this->header2,"body1"=>$this->body1,"body2"=>$this->body2,"image1"=>$this->image1,"image2"=>$this->image2,"caption1"=>$this->caption1,"caption2"=>$this->caption2);return$this->content;}privatefunction loadContent(){//Create Query Statement$this->sql="SELECT * FROM $this->tableMaster WHERE id = 1";if($result=$this->hookup->query($this->sql)){while($row=$result->fetch_assoc()){$this->css=$row['css'];$this->title=$row['title'];$this->header1=$row['header1'];$this->header2=$row['header2'];$this->body1=$row['body1']."";$this->body2=$row['body2']."";$this->image1="images/".$row['image1'];$this->image2="images/".$row['image2'];$this->caption1=$row['caption1'];$this->caption2=$row['caption2'];}$result->close();}$this->hookup->close();}}?>
The declaration line:
class PageProduct1 extends ProductTools implements Product
imbues PageProduct1 with both the properties of the ProductTools and the interface of the Product. By having the abstract class ProductTools provide the essential properties of a Product child, the properties need not be declared in the concrete product child classes and add some uniformity. At the same time the Product child implementations have the common Product interface. If you’re thinking that a single abstract class could have handled both the method and the properties, you’d be right. However, but having a separate class for properties, the same design could easily be adapted to include a whole new set of properties if need be.
You probably recognize PageProduct1 as the RetrieveBlog class from Part IV of the CMS series. About the only difference is that I created an abstract class ProductTools to store common product properties for use by any other product classes that the developer may care to add. It reduces clutter and makes it easier to make small changes. For example, one strategy considered is to create several different instances of PageProduct1, such as PageProduct2, PageProduct3 and so on. Each could simply identify a different table ID number to be called from the Client class. On the other hand, new data could be added simply by using an UPDATE SQL command to change the content of the record with an ID selected by the class.
Figure 2 shows an added page delivered as a concrete product upon a Client request, and as you can see, it looks just like the others in this series, but the content has changed:
Figure 2: Page created with Factory Method CMS
The nature of the page has not changed, but the way in which it is requested has. The request is through the Creator interface; so next we’ll take a look at the concrete creator class and the new Client class.
Request to the Creator
The real “un-coupler” participant in the Factory Method design pattern is the Creator and its implementations. In this instance, the single concrete class passes on the request from the Client for a Product. In the following listing are both the Creator abstract class and its child class, PageCreator: (Note: Product type hinting is used so that additional concrete product implementations may be called through the same interface. This is an example of the design pattern principle of program to the interface (Product) and not the implementation (PageProduct1).
At this point, you may wonder where the content of the $pageNow parameter comes from. In this case, and all along in this series actually, the Web page has been the client. It is requesting content for the HEREDOC page. So, we might as well put it where it belongs—in the Client class as shown:
The Client makes the request through the PageCreator class and then invokes the factoryMethod() to specify the product, PageProduct1. Now suppose later that you want to make more products—implementations of the Product interface. Because the request in the Creator specifies through type hinting is for the Product and not any specific implementation of the Product interface, it can handle anyProduct implementation.
You may want to review other implementations of the Factory Method on this blog for a review in understanding how everything works together. However, it comes down to Request -> Creator -> Product.
The CMS Co-Stars
In wrapping up this series on creating a CMS using a design pattern in PHP, you will find a folder full of some of the tools you’ll need for creating and maintaining the system in a folder named “Administrative.” At some point soon, I hope to implement it for the http://www.sandlight.com site, and I’d be very interested in what others have done or ideas for making it better. In the meantime enjoy exploring its possibilities.
Recent Comments