Object-Oriented PHP MOVED TO CODEWALKERS

Beginning PHP and PostgreSQL 8: From Novice to Professional

Written by W. Jason Gilmore, Robert H. Treat

Published by Apress

Chapter 6



This chapter and the next introduce what is surely PHP 5’s shining star: the vast improvements and enhancements to PHP’s object-oriented functionality. If you’ve used PHP prior to version 5, you may be wondering what the buzz is all about. After all, PHP 4 offered object-oriented capabilities, right? Although the answer to this question is technically yes, version 4’s object-oriented functionality was rather hobbled. Although the very basic premises of object-oriented programming (OOP) were offered in version 4, several deficiencies existed, including:

  1. An unorthodox object-referencing methodology
     
  2. No means for setting the scope (public, private, protected, abstract) of fields and methods 
     
  3. No standard convention for naming constructors
     
  4. Absence of object destructors 
     
  5. Lack of an object-cloning feature 
     
  6. Lack of support for interfaces

In fact, PHP 4’s adherence to the traditional OOP model is so bad that in Jason’s first book, A Programmer’s Introduction to PHP 4.0, he devoted more time to demonstrating hacks than to actually introducing useful OOP features. Thankfully, version 5 eliminates all of the aforementioned hindrances, offering substantial improvements over the original implementation, as well as a bevy of new OOP features. This chapter and the following aim to introduce these new features and enhanced functionality. Before doing so, however, this chapter briefly discusses the advantages of the OOP development model.


Note  While this and the following chapter serve to provide you with an extensive introduction to PHP’s OOP features, a thorough treatment of their ramifications for the PHP developer is actually worthy of an entire book. Conveniently, Matt Zandstra’s PHP 5 Objects, Patterns, and Practice (Apress, 2004) covers the topic in considerable detail, accompanied by a fascinating introduction to implementing design patterns with PHP and an overview of key development tools such as Phing, PEAR, and phpDocumentor.


The Benefits of OOP

The birth of object-oriented programming represented a major paradigm shift in development strategy, refocusing attention on an application’s data rather than its logic. To put it another way, OOP shifts the focus from a program’s procedural events toward the real-life entities it ultimately models. The result is an application that closely resembles the world around us.

This section examines three of OOP’s foundational concepts: encapsulation, inheritance, and polymorphism. Together, these three ideals form the basis for the most powerful programming model yet devised.

Encapsulation

Programmers are typically rabidly curious individuals. We enjoy taking things apart and learning how all of the little pieces work together. Although mentally gratifying, attaining such in-depth knowledge of an item’s inner workings isn’t a requirement. For example, millions of people use a computer every day, yet few know how it actually works. The same idea applies to automobiles, microwaves, televisions, and any number of commonplace items. We can get away with such ignorance through the use of interfaces. For example, you know that turning the radio dial allows you to change radio stations; never mind the fact that what you’re actually doing is telling the radio to listen to the signal transmitted at a particular frequency, a feat accomplished using a demodulator. Failing to understand this process does not prevent you from using the radio, because the interface takes care to hide such details. The practice of separating the user from the true inner workings of an application through well-known interfaces is known as encapsulation.

Object-oriented programming promotes the same notion of hiding the inner workings of the application, by making available well-defined interfaces from which each application component can be accessed. Rather than get bogged down in the gory details, OOP-minded developers design each application component so that it is independent from the others, which not only encourages reuse but also enables the developer to assemble components like a puzzle rather than tightly lash, or couple, them together. These well-defined interfaces are known as objects. Objects are created from a template known as a class, which is used to embody both the data and the behavior you would expect of a particular entity. Classes expose certain behaviors through functions known as methods, which in turn are used to manipulate class characteristics, known as fields. This strategy offers several advantages:

  1. The developer can change the application implementation without affecting the object user, because the user’s only interaction with the object is via its interface.
  2. The potential for user error is reduced, because of the control exercised over the user’s interaction with the application.

Inheritance

The many objects constituting our environment can be modeled using a fairly well-defined set of rules. Take, for example, the concept of an employee. Let’s begin by loosely defining an employee as somebody who contributes to the common goals of an organization. All employees share a common set of characteristics: a name, employee ID, and wage, for instance. However, there are many different classes of employees: clerks, supervisors, cashiers, and chief executive offers, among others, each of which likely possesses some superset of those characteristics defined by the generic employee definition. In object-oriented terms, these various employee classes inherit the general employee definition, including all of the characteristics and behaviors that contribute to this definition. In turn, each of these specific employee classes could, in turn, be inherited by yet another, more specific class. For example, the “clerk” type might be inherited by a day clerk and a night clerk, each of which inherits all traits specified by both the employee definition and the clerk definition. Building on this idea, you could then later create a “human” class, and then make the “employee” class a subclass of human. The effect would be that the employee class and all of its derived classes (clerk, cashier, CEO, and so on) would immediately inherit all characteristics and behaviors defined by human.

The object-oriented development methodology places great stock in the concept of inheritance. This strategy promotes code reusability, because it assumes that one will be able to use well-designed classes (i.e. classes that are sufficiently abstract to allow for reuse) within numerous applications.

Polymorphism

Polymorphism, a term originating from the Greek language that means “having multiple forms,” is perhaps the coolest feature of OOP. Simply defined, polymorphism defines OOP’s ability to redefine, or morph, a class’s characteristic or behavior depending upon the context in which it is used. This is perhaps best explained with an example.

Returning to the employee example, suppose that a behavior titled clock_in was included within the employee definition. For employees of class clerk, this behavior might involve actually using a time clock to timestamp a card. For other types of employees, “programmers” for instance, clocking in might involve signing on to the corporate network. Although both classes derive this behavior from the employee class, the actual implementation of each is dependent upon the context in which “clocking in” is implemented. This is the power of polymorphism.

These three key OOP concepts, encapsulation, inheritance, and polymorphism, are touched upon as they apply to PHP’s OOP implementation through this chapter and the next.

Key OOP Concepts

This section introduces key object-oriented implementation concepts, including PHP-specific examples.

Classes

Our everyday environment consists of innumerable entities: plants, people, vehicles, food…we could go on for hours just listing them. Each entity is defined by a particular set of characteristics and behaviors that ultimately serves to define the entity for what it is. For example, a vehicle might be defined as having characteristics such as color, number of tires, make, model, and capacity, and having behaviors such as stop, go, turn, and honk horn. In the vocabulary of OOP, such an embodiment of an entity’s defining attributes and behaviors is known as a class.

Classes are intended to represent those real-life items that you’d like to manipulate within an application. For example, if you wanted to create an application for managing a public library, you’d probably want to include classes representing books, magazines, employees, special events, patrons, and anything else that would require oversight. Each of these entities embodies a certain set of characteristics and behaviors, better known in OOP as fields and methods, respectively, that defines the entity as what it is. PHP’s generalized class creation syntax follows:

class classname
{
   
// Field declarations defined here
   
// Method declarations defined here
}

Listing 6-1 depicts a class representing employees.

Listing 6-1. Class Creation

class Staff
{
   
private $name;
   
private $title;
   
protected $wage;
  
protected function clockIn() {
      
echo "Member $this->name clocked in at ".date("h:i:s");
   
}
  
protected function clockOut() {
       
echo "Member $this->name clocked out at ".date("h:i:s") ;
   }
}

Titled Staff , this class defines three fields, name , title , and wage , in addition to two methods, clockIn and clockOut . Don’t worry if you’re not familiar with some of the grammar and syntax ( private / protected and $this , particularly); each of these topics is covered in detail later in the chapter.

Objects

A class is quite similar to a recipe, or template, that defines both the characteristics and behavior of a particular concept or tangible item. This template provides a basis from which you can create specific instances of the entity the class models, better known as objects. For example, an employee management application may include a Staff class, which serves as the template for managing employee information. Based on these specifications, you can create and maintain specific instances of the staff class, Sally and Jim , for example.


Note The practice of creating objects based on predefined classes is often referred to as class instantiation.


Objects are created using the new keyword, like this:

$employee = new Staff();

Once the object is created, all of the characteristics and behaviors defined within the class are made available to the newly instantiated object. Exactly how this is accomplished is revealed in the following sections.

Fields

Fields are attributes that are intended to describe some aspect of a class. They are quite similar to normal PHP variables, except for a few minor differences, which you’ll learn about in this section. You’ll also learn how to declare and invoke fields, and read all about field scopes.

Declaring Fields

The rules regarding field declaration are quite similar to those in place for variable declaration: essentially, there are none. Because PHP is a loosely typed language, fields don’t even necessarily need to be declared; they can simply be created and assigned simultaneously by a class object, although you’ll rarely want to do that. Instead, common practice is to declare fields at the beginning of the class. Optionally, you can assign them initial values at this time. An example follows:

class Staff
{
   
public $name = "Lackey";
   
private $wage;
}

In this example, the two fields, name and wage , are prefaced with a scope descriptor ( public or private ), a common practice when declaring fields. Once declared, each field can be used under the terms accorded to it by the scope descriptor. If you don’t know what role scope plays in class fields, don’t worry; that topic is covered later in this chapter.

Invoking Fields

Fields are referred to using the -> operator and, unlike variables, are not prefaced with a dollar sign. Furthermore, because a field’s value typically is specific to a given object, it is correlated to said object like this:

$object->field

For example, the Staff class described at the beginning of this chapter included the fields name , title , and wage . If you created an object named $employee of type Staff , you would refer to these fields like this:

$employee->name
$employee->title
$employee->wage

When you refer to a field from within the class in which it is defined, it is still prefaced with the -> operator, although instead of correlating it to the class name, you use the $this keyword. $this implies that you’re referring to the field residing in the same class in which the field is being accessed or manipulated. Therefore, if you were to create a method for setting the name field in the aforementioned Staff class, it might look like this:

function setName($name)
{
   $this->name = $name;
}

Field Scopes

PHP supports five class field scopes: public, private, protected, final, and static. The first four are introduced in this section, and the static scope is introduced in the later section, “Static Class Members.”

Public

You can declare fields in the public scope by prefacing the field with the keyword public. An example follows:

public . An example follows: You can declare fields in the public scope by prefacing the field with the keyword public. An example follows:

class Staff
{
   
public $name;
  
/* Other field and method declarations follow… */
}

Public fields can then be manipulated and accessed directly by a corresponding object, like so:

$employee = new Staff();
$employee->name = "Mary Swanson";
$name = $employee->name;
echo "New staff member: $name";

Not surprisingly, executing this code produces:

New staff member: Mary Swanson

Although this might seem like a logical means for maintaining class fields, public fields are actually generally considered taboo to OOP, and for good reason. The reason for shunning such an implementation is that such direct access robs the class of a convenient means for enforcing any sort of data validation. For example, nothing would prevent the user from assigning name like so:

$employee->name = "12345";

This is certainly not the kind of input you were expecting. To prevent such mishaps from occurring, two solutions are available. One solution involves encapsulating the data within the object, making it available only via a series of interfaces, known as public methods. Data encapsulated in this way is said to be private in scope. The second recommended solution involves the use of properties, and is actually quite similar to the first solution, although it is a tad more convenient in most cases. Private scoping is introduced next, whereas properties are discussed in the later section, “Properties.”

Private

Private fields are only accessible from within the class in which they are defined. An example follows:

class Staff
{
   
private $name;
   
private $telephone;
}

Fields designated as private are not directly accessible by an instantiated object, nor are they available to subclasses. If you want to make these fields available to subclasses, consider using the protected scope instead, introduced next. Instead, private fields must be accessed via publicly exposed interfaces, which satisfies one of OOP’s main tenets introduced at the beginning of this chapter: encapsulation. Consider the following example, in which a private field is manipulated by a public method:

<?php
  
class Staff
  
{
     
private $name;
     
public function setName($name) {
        
$this->name = $name;
     
}
   }
  
$staff = new Staff;
   $staff->setName("Mary");
?>

Encapsulating the management of such fields within a method enables the developer to maintain tight control over how that field is set. For example, you could add to the setName() method’s capabilities, to validate that the name is set to solely alphabetical characters and to ensure that it isn’t blank. This strategy is much more reliable than leaving it to the end user to provide valid information.

Protected

Just like functions often require variables intended for use only within the function, classes can include fields used for solely internal purposes. Such fields are deemed protected, and are prefaced accordingly. An example follows:

class Staff
{
   
protected $wage;
}

Protected fields are also made available to inherited classes for access and manipulation, a trait not shared by private fields. Any attempt by an object to access a protected field will result in a fatal error. Therefore, if you plan on extending the class, you should use protected fields in lieu of private fields.

Final

Marking a field as final prevents it from being overridden by a subclass, a matter discussed in further detail in the next chapter. A finalized field is declared like so:

class Staff
{
   final $ssn;
  

}

You can also declare methods as final; the procedure for doing so is described in the later section, “Methods.”

Properties

Properties are a particularly convincing example of the powerful features OOP has to offer, ensuring protection of fields by forcing access and manipulation to take place through methods, yet allowing the data to be accessed as if it were a public field. These methods, known as accessors and mutators, or more informally as getters and setters, are automatically triggered whenever the field is accessed or manipulated, respectively.

Unfortunately, PHP 5 does not offer the property functionality that you might be used to if you’re familiar with other OOP languages like C++ and Java. Therefore, you’ll need to make do with using public methods to imitate such functionality. For example, you might create getter and setter methods for the property name by declaring two functions, getName() and setName() , respectively, and embedding the appropriate syntax within each. An example of this strategy is presented at the conclusion of this section.

PHP 5 does offer some semblance of support for properties, opening up several new possibilities. This support is made available by overloading the __set and __get methods. These methods are invoked if you attempt to reference a member variable that does not exist within the class definition. Properties can be used for a variety of purposes, such as to invoke an error message, or even to extend the class by actually creating new variables on the fly. Both _get and _set are introduced in this section.

__set()

boolean __set([string property_name],[mixed value_to_assign])

The mutator, or setter method, is responsible for both hiding field assignment implementation and validating class data before assigning it to a class field. It takes as input a property name and a corresponding value, returning TRUE if the method is successfully executed, and FALSE otherwise. An example follows:

class Staff
{
   var $name;
   function __set($propName, $propValue)
   {
      
echo "Nonexistent variable: $$propName!";
   }
}

$employee = new Staff();
$employee->name = "Mario";
$employee->title = "Executive Chef";

This results in the following output:

——————————————–
Nonexistent variable: $title!
——————————————–

Of course, you could use this method to actually extend the class with new properties, like this:

class Staff
{
   var $name;
   function __set($propName, $propValue)
   {
      
$this->$propName = $propValue;
   }
}

$employee = new Staff();
$employee->name = "Mario";
$employee->title = "Executive Chef";
echo "Name: ".$employee->name;
echo "<br />";
echo "Title: ".$employee->title;

This produces:

——————————————–
Name: Mario
Title: Executive Chef
——————————————– 

_get()

boolean __get([string property_name])

The accessor, or getter method, is responsible for encapsulating the code required for retrieving a class variable. It takes as input one parameter, the name of the property whose value you’d like to retrieve. It should return the value TRUE on successful execution, and FALSE otherwise. An example follows:

class Staff
{
   var $name;
   var $city;
   protected $wage;

   function __get($propName)
  
{
      echo "__get called!<br />";
      $vars = array("name","city");
      if (in_array($propName, $vars))
      {
        
return $this->$propName;
      } else {
         return "No such variable!";
      }
   }

}

$employee = new Staff();
$employee->name = "Mario";

echo $employee->name."<br />";
echo $employee->age;

This returns the following:

——————————————–
Mario
__get called!
No such variable!
——————————————–

Creating Custom Getters and Setters

Frankly, although there are some benefits to the aforementioned __set() and __get() methods, they really aren’t sufficient for managing properties in a complex object-oriented application. Because PHP doesn’t offer support for the creation of properties in the fashion that Java or C# does, you need to implement your own methodology. Consider creating two methods for each private field, like so:

<?php
class Staff {
   private $name;
  
// Getter
  
public function getName() {
     
return $this->name;
   }
   // Setter
   public function setName($name) {
      $this->name = $name;
   }
}
?>

Although such a strategy doesn’t offer the same convenience as using properties, it does encapsulate management and retrieval tasks using a standardized naming convention. Of course, you should add additional validation functionality to the setter; however, this simple example should suffice to drive the point home.

Constants

You can define constants, or values that are not intended to change, within a class. These values will remain unchanged throughout the lifetime of any object instantiated from that class. Class constants are created like so:

const NAME = ‘VALUE’;

For example, suppose you created a math-related class that contains a number of methods defining mathematical functions, in addition to numerous constants:

class math_functions
{
  
const PI = ‘3.14159265’;
  
const E = ‘2.7182818284’;
  
const EULER = ‘0.5772156649’;
  
/* define other constants and methods here… */
}

Class constants can then be called like this:

——————————————–
echo math_functions::PI;

——————————————–

Methods

A method is quite similar to a function, except that it is intended to define the behavior of a particular class. Like a function, a method can accept arguments as input and can return a value to the caller. Methods are also invoked like functions, except that the method is prefaced with the name of the object invoking the method, like this:

$object->method_name();

In this section you’ll learn all about methods, including method declaration, method invocation, and scope.

Declaring Methods

Methods are created in exactly the same fashion as functions, using identical syntax. The only difference between methods and normal functions is that the method declaration is typically prefaced with a scope descriptor. The generalized syntax follows:

scope function functionName()
{
  
/* Function body goes here */
}

For example, a public method titled calculateSalary() might look like this:

public function calculateSalary()
{
  
return $this->wage * $this->hours;
}

In this example, the method is directly invoking two class fields, wage and hours , using the $this keyword. It calculates a salary by multiplying the two field values together, and returns the result just like a function might. Note, however, that a method isn’t confined to working solely with class fields; it’s perfectly valid to pass in arguments in the same way you can with a function.


Tip  In the case of public methods, you can forego explicitly declaring the scope and just declare the method like you would a function (without any scope).


Invoking Methods

Methods are invoked in almost exactly the same fashion as functions. Continuing with the previous example, the calculateSalary() method might be invoked like so:

$employee = new staff("Janie");
$salary = $employee->calculateSalary();

Method Scopes

PHP supports six method scopes: public, private, protected, abstract, final, and static. The first five scopes are introduced in this section. The sixth, static, is introduced in the later section, “Static Members.”

Public

Public methods can be accessed from anywhere, at any time. You declare a public method by prefacing it with the keyword public, or by foregoing any prefacing whatsoever. The following example demonstrates both declaration practices, in addition to demonstrating how public methods can be called from outside the class:

<?php 
  
class Visitors
   {
     
public function greetVisitor()
      { 
       
echo "Hello<br />";
      }
      function sayGoodbye()
      {
       
echo "Goodbye<br />";
     
}
    }
    Visitors::greetVisitor();
    $visitor = new Visitors();
    $visitor->sayGoodbye();
?>

The following is the result:

——————————————–
Hello
Goodbye
——————————————–

Private

Methods marked as private are available for use only within the originating class and cannot be called by the instantiated object, nor by any of the originating class’s subclasses. Methods solely intended to be helpers for other methods located within the class should be marked as private. For example, consider a method, called validateCardNumber(), used to determine the syntactical validity of a patron’s library card number. Although this method would certainly prove useful for satisfying a number of tasks, such as creating patrons and self-checkout, the function has no use when executed alone. Therefore, validateCardNumber() should be marked as private, like this:

private function validateCardNumber($number) {
   if (! ereg(‘^([0-9]{4})-([0-9]{3})-([0-9]{2})’) ) return FALSE;
     else return TRUE;
}

Attempts to call this method from an instantiated object result in a fatal error.

Protected

Class methods marked as protected are available only to the originating class and its subclasses. Such methods might be used for helping the class or subclass perform internal computations. For example, before retrieving information about a particular staff member, you might want to verify the employee identification number (EIN), passed in as an argument to the class instantiator. You would then verify this EIN for syntactical correctness using the verify_ein() method. Because this method is intended for use only by other methods within the class, and could potentially be useful to classes derived from Staff, it should be declared protected :

<?php
   
class Staff
   
{
      
private $ein;
      
function __construct($ein)
      
{
         
if ($this->verify_ein($ein)) {

             echo "EIN verified. Finish";
          }

       }
       protected function verify_ein($ein)
       {
         
return TRUE;
      
}
   
}
   
$employee = new Staff("123-45-6789");
?>

Attempts to call verify_ein() from outside of the class will result in a fatal error, because of its protected scope status.

Abstract

Abstract methods are special in that they are declared only within a parent class but are implemented in child classes. Only classes declared as abstract can contain abstract methods. You might declare an abstract method if you’d like to define an application programming interface (API) that can later be used as a model for implementation. A developer would know that his particular implementation of that method should work provided that it meets all requirements as defined by the abstract method. Abstract methods are declared like this:

abstract function methodName();

Suppose that you wanted to create an abstract Staff class, which would then serve as the base class for a variety of staff types (manager, clerk, cashier, and so on):

abstract class Staff
{
   abstract function hire();
   abstract function fire();
   abstract function promote();
   abstract demote();
}

This class could then be extended by the respective staffing classes, such as manager, clerk, and cashier. Chapter 7 expands upon this concept and looks much more deeply at abstract classes.

Final

Marking a method as final prevents it from being overridden by a subclass. A finalized method is declared like this:

class staff
{
   …
   final function getName() {
   …
   }
}

Attempts to later override a finalized method result in a fatal error. PHP supports six method scopes: public, private, protected, abstract, final, and static.


Note  The topics of class inheritance and the overriding of methods and fields are discussed in the next chapter.  


Type Hinting

Type hinting is a feature new to PHP 5. Type hinting ensures that the object being passed to the method is indeed a member of the expected class. For example, it makes sense that only objects of class staff should be passed to the take_lunchbreak() method. Therefore, you can preface the method definition’s sole input parameter $employee with staff , enforcing this rule. An example follows:

private function take_lunchbreak (staff $employee)
{
   …
}

Keep in mind that type hinting only works for objects. You can’t offer hints for types such as integers, floats, or strings.

Constructors and Destructors

Often, you’ll want to execute a number of tasks when creating and destroying objects. For example, you might want to immediately assign several fields of a newly instantiated object. However, if you have to do so manually, you’ll almost certainly forget to execute all of the required tasks. Object-oriented programming goes a long way toward removing the possibility for such errors by offering special methods, called constructors and destructors, that automate the object creation and destruction processes.

Constructors

You often want to initialize certain fields and even trigger the execution of methods found when an object is newly instantiated. There’s nothing wrong with doing so immediately after instantiation, but it would be easier if this were done for you automatically. Such a mechanism exists in OOP, known as a constructor. Quite simply, a constructor is defined as a block of code that automatically executes at the time of object instantiation. OOP constructors offer a number of advantages:

  1. Constructors can accept parameters, which are assigned to specific object fields at creation time.
  2. Constructors can call class methods or other functions. 
     
  3. Class constructors can call on other constructors, including those from the class parent.

This section reviews how all of these advantages work with PHP 5’s improved constructor functionality.


Note  PHP 4 also offered class constructors, but it used a different, more cumbersome syntax than that used in version 5. Version 4 constructors were simply class methods of the same name as the class they represented. Such a convention made it tedious to rename a class. The new constructor-naming convention resolves these issues. For reasons of compatibility, however, if a class is found to not contain a constructor satisfying the new naming convention, that class will then be searched for a method bearing the same name as the class; if located, this method is considered the constructor.


PHP recognizes constructors by the name __construct . The general syntax for constructor declaration follows:

function __construct([argument1, argument2, …, argumentN])
{
   
/* Class initialization code */
}

As an example, suppose you wanted to immediately populate certain book fields with information specific to a supplied ISBN. For example, you might want to know the title and author of the book, in addition to how many copies the library owns, and how many are presently available for loan. This code might look like this:

<?php
   
class book
   
{
      
private $title;
       private $isbn;
       private $copies;

       public function __construct($isbn)
       {
          $this->setIsbn($isbn);
          $this->getTitle();
          $this->getNumberCopies();
       }

       public function setIsbn($isbn)
       {
          $this->isbn = $isbn;
       }

       public function getTitle() {
          $this->title = "Beginning Python";
          print "Title: ".$this->title."<br />";
       }

       public function getNumberCopies() {
          $this->copies = "5";
          print "Number copies available: ".$this->copies."<br />";

       }
    }

    $book = new book("159059519X");
?>

This results in:

——————————————–
Title: Beginning Python
Number copies available: 5
——————————————–

Of course, a real-life implementation would likely involve somewhat more intelligent get methods (methods that query a database, for example), but the point is made. Instantiating the book object results in the automatic invocation of the constructor, which in turn calls the setIsbn() , getTitle() , and getNumberCopies() methods. If you know that such method should be called whenever a new object is instantiated, you’re far better off automating the calls via the constructor than attempting to manually call them yourself.

Additionally, if you would like to make sure that these methods are called only via the constructor, you should set their scope to private , ensuring that they cannot be directly called by the object or by a subclass.

Invoking Parent Constructors

PHP does not automatically call the parent constructor; you must call it explicitly using the parent keyword. An example follows:

<?php
class Staff
{
  
protected $name;
   protected $title;

   function __construct()
   {
      echo "<p>Staff constructor called!</p>";
   }
}

 

class Manager extends Staff
{
   function __construct()
   {
      parent::__construct();
      echo "<p>Manager constructor called</p>"; 
   }
}

 

$employee = new Manager();
?>

This results in:

—————————————
Staff constructor called!
Manager constructor called!

—————————————

Neglecting to include the call to parent::__construct() results in the invocation of only the Manager constructor, like this:

——————————————–
Manager constructor called!

——————————————–

Invoking Unrelated Constructors

You can invoke class constructors that don’t have any relation to the instantiated object, simply by prefacing __constructor with the class name, like so:

classname::__construct()

As an example, assume that the Manager and Staff classes used in the previous example bear no hierarchical relationship; instead, they are simply two classes located within the same library. The Staff constructor could still be invoked within Manager ’s constructor, like this:

Staff::__construct()

Calling the Staff constructor like this results in the same outcome as that shown in the previous example.


Note  You may be wondering why the extremely useful constructor-overloading feature, available in many OOP languages, has not been discussed. The answer is simple: PHP does not support this feature.


Destructors

Although objects were automatically destroyed upon script completion in PHP 4, it wasn’t possible to customize this cleanup process. With the introduction of destructors in PHP 5, this constraint is no more. Destructors are created like any other method, but must be titled __destruct(). An example follows:

<?php
    class Book
    {
      
private $title;
       private $isbn;
       private $copies;

       function __construct($isbn)
       {
          echo "<p>Book class instance created.</p>";
       }

       function __destruct()
       {
          echo "<p>Book class instance destroyed.</p>"; 
       }
    }

    $book = new Book("1893115852");
?>

Here’s the result:

——————————————–
Book class instance created.
Book class instance destroyed.
——————————————–

When the script is complete, PHP will destroy any objects that reside in memory. Therefore, if the instantiated class and any information created as a result of the instantiation reside in memory, you’re not required to explicitly declare a destructor. However, if less volatile data were created (say, stored in a database) as a result of the instantiation, and should be destroyed at the time of object destruction, you’ll need to create a custom destructor.

Static Class Members

Sometimes it’s useful to create fields and methods that are not invoked by any particular object, but rather are pertinent to, and are shared by, all class instances. For example, suppose that you are writing a class that tracks the number of Web page visitors. You wouldn’t want the visitor count to reset to zero every time the class was instantiated, and therefore you would set the field to be of the static scope:

<?php
    class visitors
    {
       private static $visitors = 0;

       function __construct()
       {
          self::$visitors++;
       }
          static function getVisitors()
       {
          return self::$visitors;
       }

    }
    /* Instantiate the visitors class. */
    $visits = new visitors();

    echo visitors::getVisitors()."<br />";
    /* Instantiate another visitors class. */
    $visits2 = new visitors();

    echo visitors::getVisitors()."<br />";

?>

The results are as follows:

——————————————–
1
2
——————————————–

Because the $visitors field was declared as static , any changes made to its value (in this case via the class constructor) are reflected across all instantiated objects. Also note that static fields and methods are referred to using the self keyword and class name, rather than via the this and arrow operators. This is because referring to static fields using the means allowed for their “regular” siblings is not possible, and will result in a syntax error if attempted.


Note  You can’t use $this within a class to refer to a field declared as static .

 


 

The instanceof Keyword

Another newcomer to PHP 5 is the instanceof keyword. With it, you can determine whether an object is an instance of a class, is a subclass of a class, or implements a particular interface, and do something accordingly. For example, suppose you wanted to learn whether an object called manager is derived from the class Staff :

$manager = new Staff();

if ($manager instanceof staff) echo "Yes";

There are two points worth noting here. First, the class name is not surrounded by any sort of delimiters (quotes). Including them will result in a syntax error. Second, if this comparison fails, then the script will abort execution! The instanceof keyword is particularly useful when you’re working with a number of objects simultaneously. For example, you might be repeatedly calling a particular function, but want to tweak that function’s behavior in accordance with a given type of object. You might use a case statement and the instanceof keyword to manage behavior in this fashion.

Helper Functions

A number of functions are available to help the developer manage and use class libraries. These functions are introduced in this section.

class_exists()

boolean class_exists(string class_name)

The class_exists() function returns TRUE if the class specified by class_name exists within the currently executing script context, and returns FALSE otherwise.

get_class()

string get_class(object object)

The get_class() function returns the name of the class to which object belongs, and returns FALSE if object is not an object.

get_class_methods()

array get_class_methods (mixed class_name)

The get_class_methods() function returns an array containing all method names defined by the class class_name .

get_class_vars()

array get_class_vars (string class_name)

The get_class_vars() function returns an associative array containing the names of all fields and their corresponding values defined within the class specified by class_name .

get_declared_classes()

array get_declared_classes(void)

The function get_declared_classes() returns an array containing the names of all classes defined within the currently executing script. The output of this function will vary according to how your PHP distribution is configured. For instance, executing get_declared_classes() on a test server produces a list of 63 classes.

get_object_vars()

array get_object_vars(object object)

The function get_object_vars() returns an associative array containing the defined fields available to object , and their corresponding values. Those fields that don’t possess a value will be assigned NULL within the associative array.

get_parent_class()

string get_parent_class(mixed object)

The get_parent_class() function returns the name of the parent of the class to which object belongs. If object ’s class is a base class, then that class name will be returned.

interface_exists()

boolean interface_exists(string interface_name [, boolean autoload])

The interface_exists() function determines whether an interface exists, returning TRUE if it does and FALSE otherwise.

is_a()

boolean is_a(object object, string class_name)

The is_a() function returns TRUE if object belongs to a class of type class_name , or if it belongs to a class that is a child of class_name . If object bears no relation to the class_name type, FALSE is returned.

is_subclass_of()

boolean is_subclass_of (object object, string class_name)

The is_subclass_of() function returns TRUE if object belongs to a class inherited from class_name , and returns FALSE otherwise.

method_exists()

boolean method_exists(object object, string method_name)

The method_exists() function returns TRUE if a method named method_name is available to object , and returns FALSE otherwise.

Autoloading Objects

For organizational reasons, it’s common practice to place each class in a separate file. Returning to the library scenario, suppose the management application called for classes representing books, employees, events, and patrons. Tasked with this project, you might create a directory named classes and place the following files in it: Books.class.php, Employees.class.php , Events.class.php , and Patrons.class.php . While this does indeed facilitate class management, it also requires that each separate file be made available to any script requiring it, typically through the require_once() statement. Therefore, a script requiring all four classes would require that the following statements be inserted at the beginning:

require_once("classes/Books.class.php"); require_once("classes/Employees.class.php"); require_once("classes/Events.class.php"); require_once("classes/Patrons.class.php");

Managing class inclusion in this manner can become rather tedious, and adds an extra step to the already often complicated development process. To eliminate this additional task, the concept of autoloading objects was introduced in PHP 5. Autoloading allows you to define a special __autoload function that is automatically called whenever a class is referenced that hasn’t yet been defined in the script. Returning to the library example, you can eliminate the need to manually include each class file by defining the following function:

function __autoload($class) {
   
require_once("classes/$class.class.php");
}

Defining this function eliminates the need for the require_once() statements, because when a class is invoked for the first time, __autoload() will be called, loading the class according to the commands defined in __autoload() . This function can be placed in some global application configuration file, meaning only that function will need to be made available to the script.


Note  The require_once() function and its siblings are introduced in Chapter 10.


Summary

This chapter introduced object-oriented programming fundamentals, followed by an overview of PHP’s basic object-oriented features, devoting special attention to those enhancements and additions that are new to PHP 5.

The next chapter expands upon this introductory information, covering topics such as inheritance, interfaces, abstract classes, and more.

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

chat sex hikayeleri Ensest hikaye