Abstract Classes in PHP: Setting Up a Concrete Example

Welcome to part two of the series “Abstract classes in PHP.” In three tutorials, this series introduces the key concepts of abstract classes in PHP 4-PHP 5, and explores their application and use in different object-oriented development environments. Whether you’re an experienced PHP developer wanting to fill in some gaps related to abstract classes, or only a beginner starting to taste the power of object-based programming in PHP, hopefully you’ll find this series enjoyable and instructive.

Introduction

As you’ll probably recall, in the first article I thoroughly explained the key points for implementing abstract classes in PHP 4, and demonstrated different methods of using them within a PHP application. Since PHP 4 doesn’t offer true support for abstract classes, that is, classes that can’t (and shouldn’t) be instantiated, I went through the development of different approaches for preventing a specific class from direct instantiation. In accordance with this situation, I illustrated a few common approaches to prevent a class from being instantiated, ranging from including a “die()” statement inside the class constructor, to developing more polished techniques, such as utilizing a combination of the “get_class()” and “is_subclass()” PHP built-in functions.

As you know, this last method was also aimed at preventing a class from being instantiated from non child classes. This implies having a decent approach for using abstract classes, particularly in PHP 4 programming environments, where such classes aren’t natively supported.

Now, returning to this second installment of the series, and assuming that abstract classes aren’t foreign concepts to you any longer, I’ll go one step further in the corresponding learning curve.  I will set up a couple of more helpful examples, which I hope will serve as an introduction to using PHP 4 abstract classes in some concrete situations, something definitely much closer to the needs that most PHP developers have to face on a daily basis.

Right, having defined the objectives of this tutorial, it’s time to move on and learn how abstract classes can be put to work in some concrete situations. Let’s get started.

{mospagebreak title=Setting up a concrete example: Defining the hierarchy of classes}

To illustrate how you can implement abstract classes in a concrete situation, what I’ll do next is set up an example, which will create a well-structured hierarchy of classes aimed at processing data coming from distinct sources. On top of this hierarchy, I’ll define an abstract, highly generic data processing class, which for obvious reasons won’t be able to be instantiated. Additionally, this class will expose three generic methods for converting data to different formats, but won’t provide explicit definitions for each of them (known as abstract methods).

In accordance with the concepts deployed in the first tutorial of this series, I’ll derive two subclasses from the base abstract class, by providing a concrete definition for all the generic methods inherited from the corresponding parent class. Sounds confusing? It’s not at all. Trust me. I’ll begin by defining the base abstract class “dataProcessor()”, which looks like this:

// define abstract class ‘dataProcessor’
class dataProcessor{
        function dataProcessor(){
                if(get_class($this)==’dataProcessor’||!
is_subclass_of($this)){
                    trigger_error(‘This class is abstract.It
cannot be instantiated!’,E_USER_ERROR);
                }
        }
        // define generic methods
        function toString(){}
        function toArray(){}
        function toXML(){}
}

As the above example shows, the abstract “dataProcessor” class has three empty methods, “toString()”, “toArray()” and “toXML()” respectively, aside from the corresponding constructor. Meeting the requirements of abstract classes, these methods don’t expose a specific definition themselves, because the base class only outlines the properties and methods of generic “dataProcessor” objects. Any further definition of these methods will be specifically provided within the pertinent child classes, which will implement a determined behavior in accordance with the functionality expected of each derived subclass.

Once the abstract “dataProcessor” class has been defined, it’s easy to see that each subclass will expose a concrete definition for the “toString()”, “toArray()” and “toXML()” methods. Since this process will be understood best by example, let’s move on together and derive the first child class, which I’ve called “resultProcessor”, responsible for processing MySQL result sets.

{mospagebreak title=Deriving subclasses from the parent abstract class: defining the “resultProcessor” class}

As I stated before, the sample “dataProcessor” class is in fact a highly generic blueprint, seated on top of the class hierarchy; this comes in useful for creating subclasses that implement a specific functionality. Now that the overall features of any data processor object have been defined, we next need to derive a subclass that provides a concrete implementation for each of the empty methods that you saw previously.

Considering this situation, here’s the definition for the “resultProcessor” child class, which as you’ll see, exposes a concrete definition for each method inherited from its parent class. Take a look:

// derive ‘resultProcessor’ class from ‘dataProcessor’
class resultProcessor extends dataProcessor{
 var $result;
 function resultProcessor($result){
  if(get_resource_type($result)!=’mysql result’){
   trigger_error(‘Invalid MySQL result’,E_USER_ERROR);
   exit();
  }
  $this->result=$result;
 }
 // returns database table data as string
 function toString(){
  $data=”;
  while($row=mysql_fetch_row($this->result)){
   foreach($row as $col){
    $data.=$col;
   }
   $data.=”n”;
  }
  return $data;
 }
 // returns database table data as array
 function toArray(){
  $data=array();
  while($row=mysql_fetch_row($this->result)){
   $data[]=$row;
  }
  return $data;
 }
 // returns database table data as XML
 function toXML(){
  $xml='<?xml version=”1.0″ encoding=”iso-8859-1″?>’.”n”;
  $xml.='<tabledata>’.”n”;
  $data=$this->toArray();
  foreach($data as $row=>$value){
   foreach($value as $field){
    $xml.='<fieldnode>’.$field.'</fieldnode>’.”n”;
   }
  }
  $xml.='</tabledata>';
  return $xml;
 }
}

With reference to the above child class, definitely there are many things worth noting here. Since this class only processes MySQL result sets, the constructor first checks to see whether its incoming parameter $result is really a MySQL result set. The checking code below illustrates this condition:

if(get_resource_type($result)!=’mysql result’){
 trigger_error(‘Invalid MySQL result’,E_USER_ERROR);
 exit();
}

After verifying that a real MySQL data set has been passed on as parameter, the class simply assigns it as the only property. Indeed, this is a short and efficient process.

Now, let’s move on and pay attention to the next class method, “toString()”, which takes the provided MySQL result set and returns it in a string format, where each row of the data set is delimited by a new line (n) character:

function toString(){
       $data=”;
 while($row=mysql_fetch_row($this->result)){
  foreach($row as $col){
   $data.=$col;
  }
  $data.=”n”;
 }
 return $data;
}

You’ll remember from my schematic “dataProcessor” class, that each method for processing data wasn’t explicitly defined. However, in consonance with the definition of an abstract class, the derived “resultProcessor” class does expose a specific definition for each pertinent method. Now, do you see how child classes implement specifically all the generic methods declared within the base abstract class? I hope you do.

In a similar way, the remaining methods, “toArray()” and “toXML()” in question, expose concrete definitions, as you can appreciate from the snippet below:

function toArray(){
 $data=array();
 while($row=mysql_fetch_row($this->result)){
  $data[]=$row;
 }
 return $data;
}
// returns database table data as XML
function toXML(){
 $xml='<?xml version=”1.0″ encoding=”iso-8859-1″?>’.”n”;
 $xml.='<tabledata>’.”n”;
 $data=$this->toArray();
 foreach($data as $row=>$value){
  foreach($value as $field){
   $xml.='<fieldnode>’.$field.'</fieldnode>’.”n”;
  }
 }
 $xml.='</tabledata>';
 return $xml;
}

The subclass that I just created should clarify any questions regarding the appropriate implementation of abstract classes in PHP 4. After all, this isn’t a hard-to-grasp concept. However, to dissipate further doubts, let’s expand the previous example and derive another child class from the “dataProcessor” class, so you can see how the same generic methods you learned earlier are defined in a different way. Curious about how this is done? Right, keep on reading.

{mospagebreak title=More subclasses ahead: defining the “fileProcessor” class}

In order to keep the hierarchy of sample classes pretty balanced, I’m going to derive another child class from the parent “dataProcessor” class, so you can understand how the same generic methods can be implemented differently by this subclass. For this reason, I’ll define the “fileProcessor” class, whose signature is listed below:

class fileProcessor extends dataProcessor{
 var $file;
 function fileProcessor($file){
  if(!file_exists($file)){
   trigger_error(‘Invalid file!’,E_USER_ERROR);
   exit();
  }
  $this->file=$file;
 }
 // returns filedata as string with <br /> tags
 function toString(){
  return nl2br(file_get_contents($this->file));
 }
 // returns file data as array
 function toArray(){
  return file($this->file);
 }
 // returns file data as XML
 function toXML(){
  $xml='<?xml version=”1.0″ encoding=”iso-8859-1″?>’.”n”;
  $xml.='<filedata>’.”n”;
  $filedata=$this->toArray();
  foreach($filedata as $row){
   $xml.='<filenode>’.trim($row).'</filenode>’.”n”;
  }
  $xml.='</filedata>';
  return $xml;
 }
}

As you can see, here the above child class provides specific implementations for all the generic methods originally defined within the abstract class, which I find very useful for creating a simple file processor. Stripped down to its bare bones, this class accepts the name of the file for processing and uses each one of its respective methods for returning file data in different formats.

Even when all class methods are very simple and understandable, it’s worth noting how they perform different tasks, according to the specific implementation within the two subclasses that I just created.

Additionally, if you’re pretty familiar with the major pillars of object-oriented programming, then you’ll realize that both “resultProcessor” and “fileProcessor” classes will spawn polymorphic objects, since they use the same set of methods, but actually perform different operations. I’m sure you’ll agree with me that this is a very cool and powerful concept.

So far, I’ve derived two subclasses from one base abstract class, something that hopefully has contributed to expanding your knowledge of using abstract classes in PHP 4. However, wouldn’t it be a nice corollary for this article to include all the sample classes in one script and spawn some objects? Right, let’s jump into the next section and see how these classes work together.

{mospagebreak title=Assembling the pieces: putting the classes to work together}

As I said before, let’s first list the sample “dataProcessor” abstract class and its corresponding subclasses, and then instantiate some objects and use some of their methods. Here are all the sample classes you learned previously:

// define base abstract class
class dataProcessor{
 function dataProcessor(){
  if(get_class($this)==’dataProcessor’||!is_subclass_of($this)){
           trigger_error(‘This class is abstract.It cannot be
instantiated!’,E_USER_ERROR);
          }
 }
 function toString(){}
 function toArray(){}
 function toXML(){}
}
// derive ‘resultProcessor’ class from ‘dataProcessor’
class resultProcessor extends dataProcessor{
 var $result;
 function resultProcessor($result){
  if(get_resource_type($result)!=’mysql result’){
   trigger_error(‘Invalid MySQL result’,E_USER_ERROR);
   exit();
  }
  $this->result=$result;
 }
 // returns database table data as string
 function toString(){
  $data=”;
  while($row=mysql_fetch_row($this->result)){
   foreach($row as $col){
    $data.=$col;
   }
   $data.=”n”;
  }
  return $data;
 }
 // returns database table data as array
 function toArray(){
  $data=array();
  while($row=mysql_fetch_row($this->result)){
   $data[]=$row;
  }
  return $data;
 }
 // returns database table data as XML
 function toXML(){
  $xml='<?xml version=”1.0″ encoding=”iso-8859-1″?>’.”n”;
  $xml.='<tabledata>’.”n”;
  $data=$this->toArray();
  foreach($data as $row=>$value){
   foreach($value as $field){
    $xml.='<fieldnode>’.$field.'</fieldnode>’.”n”;
   }
  }
  $xml.='</tabledata>';
  return $xml;
 }
}
// derivate ‘fileProcessor’ class from ‘dataProcessor’
class fileProcessor extends dataProcessor{
 var $file;
 function fileProcessor($file){
  if(!file_exists($file)){
   trigger_error(‘Invalid file!’,E_USER_ERROR);
   exit();
  }
  $this->file=$file;
 }
 // returns filedata as string with <br /> tags
 function toString(){
  return nl2br(file_get_contents($this->file));
 }
 // returns file data as array
 function toArray(){
  return file($this->file);
 }
 // returns file data as XML
 function toXML(){
  $xml='<?xml version=”1.0″ encoding=”iso-8859-1″?>’.”n”;
  $xml.='<filedata>’.”n”;
  $filedata=$this->toArray();
  foreach($filedata as $row){
   $xml.='<filenode>’.trim($row).'</filenode>’.”n”;
  }
  $xml.='</filedata>';
  return $xml;
 }
}

Having listed all the classes you learned before, I’ll create a simple text file, “books.txt”, which is populated with data about a few programming books:

PHP and MySQL Web Development – Luke Welling and Laura Thompson
JavaScript Learning Guide – Tom Negrino and Dori Smith
Java How to program – Deitel and Deitel

Now, see what happens when I spawn a “fileProcessor” object and call its methods:

// instantiate ‘fileProcessor’ object
$fproc=&new fileProcessor(books.txt’);
// display data as string
echo $fproc->toString();

The above scripts outputs the following source code:

PHP and MySQL Web Development – Luke Welling and Laura Thompson<br />
JavaScript Learning Guide – Tom Negrino and Dori Smith<br />
Java How to program – Deitel and Deitel

Next, I’ll use the “toArray()” method, as follows:
echo $fproc->toArray();
And the output is the following:
Array

Finally, take a look at the corresponding output, when I invoke the “toXML()” method:

header(‘Content-Type: text/xml’);
echo $fproc->toXML();

<?xml version=”1.0″ encoding=”iso-8859-1″ ?>
<filedata>
<filenode>PHP and MySQL Web Development – Luke Welling and Laura
Thompson</filenode>
<filenode>JavaScript Learning Guide – Tom Negrino and Dori
Smith</filenode>
<filenode>Java How to program – Deitel and Deitel</filenode>
</filedata>

Although the above code samples look really simple, they allow me to demonstrate how all the inherited methods implement a concrete functionality within the respective child classes.

Additionally, coming to the “resultProcessor” class, below there are some examples that show the values returned by the different methods, after inserting some records into a sample “movies” database table:

// include MySQL class file
require_once ‘mysqlclass.php';
// connect to MySQL
$db=&new MySQL(array(‘host’=>’host’,’user’=>’user’,’password’=>’password’,
‘database’=>’database’));
// create $result object
$result=$db->query(“SELECT * FROM movies”);
// instantiate ‘resultProcessor’ object & get MySQL result set
$resProc=&new resultProcessor($result->getQueryResource());

// display dataset as string
echo $resProc->toString();

1 The Shinning Jack Nicholson 2 Carrie Sissy Spacek 3 Misery Kathy Bates

// get dataset as array
echo $resProc->toArray();

Array

//get dataset as XML
header(‘Content-Type: text/xml’);
echo $resProc->toXML();

<?xml version=”1.0″ encoding=”iso-8859-1″ ?>
<tabledata>
<fieldnode>1</fieldnode>
<fieldnode>The Shinning</fieldnode>
<fieldnode>Jack Nicholson</fieldnode>
<fieldnode>2</fieldnode>
<fieldnode>Carrie</fieldnode>
<fieldnode>Sissy Spacek</fieldnode>
<fieldnode>3</fieldnode>
<fieldnode>Misery</fieldnode>
<fieldnode>Kathy Bathes</fieldnode>
</tabledata>

As you can see, I’ve provided you with some instructive examples which demonstrate a correct implementation of an abstract class in PHP 4, after deriving a couple of child classes which are responsible for processing file data, as well as MySQL result sets. As usual, feel free to study the sample codes and use them to start writing your own abstract classes.

Closing Time

We’re finished, at least for the moment. In this second part of this series, I hope you learned how to implement an abstract, highly generic class, by creating a base class on top of the corresponding hierarchy, and next deriving a couple of subclasses, which provide concrete definitions for each inherited method.

Over the final tutorial, I’ll explain by copious hands-on examples how to use abstract classes in PHP 5, along with their strong relationship with members visibility. So, see you in the last article!

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye