© Frank M. Kromann 2018
Frank M. KromannBeginning PHP and MySQLhttps://doi.org/10.1007/978-1-4302-6044-8_6

6. Object-Oriented PHP

Frank M. Kromann1 
(1)
Aliso Viejo, CA, USA
 

Although PHP did not start out as an object-oriented language, over the years a great deal of effort has been put into adding many of the object-oriented features found in other languages. This chapter and the following aim to introduce these features. Before doing so, let’s consider the advantages of the object-oriented programming (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 Objects, Patterns, and Practice, Fifth Edition (Apress, 2016) covers the topic in 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

Object-oriented programming places emphasis on the application’s objects and their interactions. An object can be thought of as a virtual representation of some real-world entity, such as an integer, spreadsheet, or form text field, bundling together the entity’s properties and behaviors into a singularly independent structure. When embracing an object-oriented approach to developing applications, you’ll create these objects in such a way that when used together, they form the “world” your application is intended to represent. The advantages of such an approach are many, including enhanced code reusability, testability, and scalability. The reasoning behind why OOP bestows such advantages will become more apparent as you work through not only this and the following chapter, but also through much of the remainder of this book since an object-oriented approach will be embraced whenever practical.

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

Encapsulation

Programmers generally enjoy taking things apart and learning how all of the little pieces work together. Although gratifying, attaining such in-depth knowledge of an item’s inner workings isn’t a precursory requirement to programming proficiency. For example, millions of people use a computer every day, yet few know how it actually works. The same idea applies to automobiles, microwaves, and any number of other items. We can get away with such ignorance through the use of interfaces. For example, you know that turning the radio’s tuning dial or using the scan button 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 gracefully hides 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 publishing well-defined interfaces from which certain object attributes and behaviors can be accessed. 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 pieces like a puzzle rather than tightly lash, or couple, them together. These pieces are known as objects, and objects are created from a template known as a class, which specifies what sorts of data and behaviors one would expect from the typical object generated (a process known as instantiation) from its class template. This strategy offers several advantages:
  • The developer can more effectively go about maintaining and improving class implementations without affecting the parts of the application that interact with the objects because the user’s only interaction with the object is via its well-defined interface.

  • The potential for user error is reduced because of the control exercised over the user’s interaction with the application. For instance, a typical class intended to represent a web site user might include a behavior for saving an e-mail address. If that behavior includes logic for ensuring the e-mail address is syntactically valid, then it will not be possible for a user to mistakenly assign a blank e-mail address or one that isn’t valid, such as carli#example.com.

Inheritance

The many objects constituting your environment can be modeled using a well-defined set of requirements. For instance, all employees share a common set of characteristics: name, employee ID, and wage. However, there are many different types of employees: clerks, supervisors, cashiers, and chief executive officers, among others, each of which likely possesses some superset of those characteristics defined by this generic employee definition. In object-oriented terms, each specialized employee type could inherit the general employee definition, and additionally further extend the definition to suit the specific needs of each type. For example, the CEO (Chief Executive Officer) type might additionally identify information regarding the stock options granted. 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, Executive, etc.) 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.

I’ll formally delve into the topic of inheritance in the next chapter; however, I will unavoidably occasionally make mention of parent and child classes within this chapter. Don’t be concerned if these occasional references don’t make sense, as all will become crystal clear by the end of the next chapter.

Polymorphism

Polymorphism, a term originating from the Greek language that means “having multiple forms,” defines OOP’s ability to redefine, or morph, a class’s characteristic or behavior depending upon the context in which it is used.

Returning to the example, suppose that a behavior pertaining to signing in for one’s shift was included within the employee definition. For employees of type (or class) Clerk, this behavior might involve actually using a time clock to timestamp a card. For other types of employees, Programmer for instance, signing in might involve logging 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 “signing in” is implemented. This is the power of polymorphism. In PHP this concept is implemented through interface classes that define the name and parameter list of one or more methods. The actual implementation of these methods is handled by each class that implements an interface.

Key OOP Concepts

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

Classes

Our everyday environment consists of countless entities: plants, people, vehicles, food... I 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 seating 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 want 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 participate in the process of managing a library. Each of these entities embodies a certain set of characteristics and behaviors, better known in OOP as properties and methods, respectively, that define the entity as what it is. PHP’s generalized class creation syntax follows:
class Class_Name
{
    // Property declarations defined here
    // Method declarations defined here
}
Listing 6-1 depicts a class representing a library employee.
class Employee
{
    private $name;
    private $title;
    public function getName() {
        return $this->name;
    }
    public function setName($name) {
        $this->name = $name;
    }
    public function sayHello() {
        echo "Hi, my name is {$this->getName()}.";
    }
}
Listing 6-1

Class Creation

Titled Employee, this class defines two properties: name and title, in addition to three methods, getName(), setName(), and sayHello(). Don’t worry if you’re not familiar with some or any of the syntax; it will become clear later in the chapter.

Note

While no coding standard is provided by PHP, there are a number of standards available in the community. The first one came from PEAR ( https://pear.php.net/manual/en/standards.php ), but later ones are getting more traction as they are adopted by many different frameworks. These are managed and documented by PHP-FIG ( https://www.php-fig.org/ ), an organization that provides standards for coding and many other aspects of using the programming language.

Objects

A class 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 an Employee class. You can then call upon this class to create and maintain specific instances such as Sally and Jim.

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 Employee;

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.

Properties

Properties are attributes that describe a particular value, such as name, color, or age. They are quite similar to standard PHP variables, except for a few key differences, which you’ll learn about in this section. You’ll also learn how to declare and invoke properties and how to restrict access using property scopes.

Declaring Properties

The rules regarding property declaration are quite similar to those in place for variable declaration; essentially, there are none. Because PHP is a loosely typed language, properties 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 because it would detract from the code’s readability. Instead, a common practice is to declare properties at the beginning of the class. Optionally, you can assign them initial values at this time. An example follows:
class Employee
{
    public $name = "John";
    private $wage;
}

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

Invoking Properties

Properties are referred to using the -> operator and, unlike variables, are not prefaced with a dollar sign. Furthermore, because a property’s value typically is specific to a given object, it is correlated to that object like this:
$object->property
For example, the Employee class includes the properties name, title, and wage. If you create an object named $employee of type Employee, you would refer to its public properties like this:
$employee->name
$employee->title
$employee->wage
When you refer to a property 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 property residing in the same class in which the property is being accessed or manipulated. Therefore, if you were to create a method for setting the name property in the Employee class, it might look like this:
function setName($name)
{
    $this->name = $name;
}

Managing Property Scopes

PHP supports three class property scopes: public, private, and protected.

Public Properties
You can declare properties in the public scope by prefacing the property with the keyword public . An example follows:
class Employee
{
    public $name;
    // Other property and method declarations follow...
}

This example defines a simple class with a single public property. In order to use the class, it must be instantiated to an object. This is done with the use of the new operator. $employee = new Employee(); The parentheses after the class name are used to provide parameters to the constructor. In this case, there is no constructor defined so there are no parameters.

Public properties can then be accessed and manipulated directly via the corresponding object, like so:
$employee = new Employee();
$employee->name = "Mary Swanson";
$name = $employee->name;
echo "New employee: $name";
Executing this code produces the following:
New employee: Mary Swanson
Although this might seem like a logical means for maintaining class properties, public properties are actually generally considered taboo, 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 a name like so:
$employee->name = "12345";

This is certainly not the kind of input you are expecting. To prevent such occurrences, 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 usually 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, and the section on properties soon follows.

Private Properties
Private properties are only accessible from within the class in which they are defined. An example follows:
class Employee
{
    private $name;
    private $telephone;
}
Properties designated as private are only directly accessible by an object instantiated from the class, but are they are not available to objects instantiated from child classes (the concept of a child class is introduced in the next chapter). If you want to make these properties available to child classes, consider using the protected scope instead, introduced next. Note that private properties 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 property is manipulated by a public method:
   class Employee
   {
      private $name;
      public function setName($name) {
         $this->name = $name;
      }
   }
   $employee = new Employee;
   $employee->setName("Mary");

Encapsulating the management of such properties within a method enables the developer to maintain tight control over how that property is set. For example, you could enhance 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 practical than leaving it to the end user to provide valid information.

Protected Properties
Just like functions often require variables intended for use only within the function, classes can include properties used for solely internal purposes. Such properties are deemed protected and are prefaced accordingly. An example follows:
class Employee
{
     protected $wage;
}

Protected properties are also made available to inherited classes for access and manipulation, a trait not shared by private properties. Therefore, if you plan on extending the class, you should use protected properties in lieu of private properties.

The following example shows how a class can extend another class and gain access to all protected properties from the parent class as if these were defined on the child class.
class Programmer extends Employee
{
     public function bonus($percent) {
        echo "Bonud = " . $this->wage * $percent / 100;
    }
}

Property Overloading

Property overloading continues to protect properties by forcing access and manipulation through public methods, yet allowing the data to be accessed as if it were a public property. These methods, known as accessors and mutators, or more informally, but more widely known as getters and setters, are automatically triggered whenever the property is accessed or manipulated, respectively.

Unfortunately, PHP does not offer the property overloading features that you might be used to if you’re familiar with other OOP languages such as 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 introduced some semblance of support for property overloading, done 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.

Setting Properties with the __set() Method

The mutator, or setter method, is responsible for both hiding property assignment implementation and validating class data before assigning it to a class property. Its prototype follows:
public void __set([string name], [mixed value])
The __set() method takes as input a property name and a corresponding value. An example follows:
class Employee
{
    public $name;
    function __set($propName, $propValue)
    {
        echo "Nonexistent variable: $$propName!";
    }
}
$employee = new Employee;
$employee->name = "Mario";
$employee->title = "Executive Chef";
This results in the following output:
Nonexistent variable: $title!
You could use this method to actually extend the class with new properties, like this:
class Employee
{
    public $name;
    public function __set($propName, $propValue)
    {
        $this->$propName = $propValue;
    }
}
$employee = new Employee;
$employee->name = "Mario";
$employee->title = "Executive Chef";
echo "Name: {$employee->name}<br />";
echo "Title: {$employee->title}";
This produces the following:
Name: Mario
Title: Executive Chef

Getting Properties with the __get() Method

The accessor, or mutator method, is responsible for encapsulating the code required for retrieving a class variable. Its prototype follows:
public mixed __get([string name])
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 Employee
{
    public $name;
    public $city;
    protected $wage;
    public 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 Employee();
$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 __set() and __get() methods, they really aren’t sufficient for managing properties in a complex object-oriented application, primarily because most properties are going to require their own specific validation logic. 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 solution. Consider creating two methods for each private property, like so:
<?php
    class Employee
    {
        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 create a math-related class that contains a number of methods defining mathematical functions, in addition to numerous constants:
class mathFunctions
{
    const PI = '3.14159265';
    const E = '2.7182818284';
    const EULER = '0.5772156649';
    // Define other constants and methods here...
}
Class constants are defined as part of the class definition and the values can’t be changed at runtime as you can with properties or as is known for other constants that are defined with the define() function. Class constants are considered static members of the class and as such they are accessed with the use of :: instead of ->. More about static properties and methods later. Class constants can then be called like this:
echo mathFunctions::PI;

Methods

A method is quite similar to a function, except that it is intended to define the behavior of a particular class. You’ve already used plenty of methods in earlier examples, many of which were related to the setting and getting of object properties. 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->methodName();

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 properties, wage and hours, using the $this keyword . It calculates a salary by multiplying the two property values together and returns the result just like a function might. Note, however, that a method isn’t confined to working solely with class properties; it’s perfectly valid to pass in arguments in the same way that you can with a function.

There are a number of reserved method names that are used for methods with a special purpose. These are referred to as magic methods and the names are: __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone(), and __debugInfo(). These methods are defined later and none of them are needed to create a class.

Invoking Methods

Methods are invoked in almost exactly the same fashion as functions. Continuing with the previous example, the calculateSalary() method would be invoked like so:
$employee = new Employee("Janie");
$salary = $employee->calculateSalary();

Method Scopes

PHP supports three method scopes: public, private, and protected.

Public Methods
Public methods can be accessed from anywhere at any time. You declare a public method by prefacing it with the keyword public. The following example demonstrates both declaration practices, in addition to demonstrating how public methods can be called from outside the class:
<?php
    class Visitor
    {
        public function greetVisitor()
        {
            echo "Hello!";
        }
}
    $visitor = new Visitor();
    $visitor->greetVisitor();
?>
The following is the result:
Hello!
Private Methods
Methods marked as private are available for use only within methods defined in the same class but are not available to methods defined on a child class. 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() that is 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, and then used within, for instance, the setCardNumber() method, as shown in Listing 6-2 below:
{
    if $this->validateCardNumber($number) {
        $this->cardNumber = $number;
        return TRUE;
    }
    return FALSE;
}
private function validateCardNumber($number)
{
    if (!preg_match('/^([0-9]{4})-([0-9]{3})-([0-9]{2})/', $number) ) return FALSE;
        else return TRUE;
}
Listing 6-2

public function setCardNumber($number)

Attempts to call the validateCardNumber() method from outside of the instantiated object result in a fatal error.

Protected
Class methods marked as protected are available only to the originating class and its child classes. 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 constructor. You would then verify this EIN for syntactical correctness using the verifyEIN() method . Because this method is intended for use only by other methods within the class and could potentially be useful to classes derived from Employee, it should be declared as protected, like so:
<?php
    class Employee
    {
        private $ein;
        function __construct($ein)
        {
            if ($this->verifyEIN($ein)) {
                echo "EIN verified. Finish";
            }
        }
        protected function verifyEIN($ein)
        {
            return TRUE;
        }
    }
    $employee = new Employee("123-45-6789");
?>

Attempts to call verifyEIN() from outside of the class or from any child classes 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, and abstract classes can’t be instantiated. They serve as a base definition for sub or child classes. You might declare an abstract method if you want 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 want to create an abstract Employee class, which would then serve as the base class for a variety of employee types (manager, clerk, cashier, etc.):
abstract class Employee
{
    abstract function hire();
    abstract function fire();
    abstract function promote();
    abstract function demote();
}

This class could then be extended by the respective employee 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 Employee
{
    final function getName() {
    ...
    }
}

Attempts to later override a finalized method result in a fatal error.

Note

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

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 properties 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 properties 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:
  • Constructors can accept parameters, which can be assigned to specific object properties at creation time.

  • Constructors can call class methods or other functions.

  • Class constructors can call on other constructors, including those from the class parent.

PHP recognizes constructors by the name __construct (a double underscore precedes the constructor keyword). The general syntax for constructor declaration follows:
function __construct([argument1, argument2, ..., argumentN])
{
     // Class initialization code
}
As an example, suppose you want to immediately set a book’s ISBN when creating a new Book object. You can save the hassle of executing the setIsbn() method after creating the object by using a constructor. The code might look like this:
<?php
    class Book
    {
        private $title;
        private $isbn;
        private $copies;
        function __construct($isbn)
        {
            $this->setIsbn($isbn);
        }
        public function setIsbn($isbn)
        {
            $this->isbn = $isbn;
        }
    }
    $book = new Book("0615303889");
?>

With the constructor defined , instantiating the book object results in the automatic invocation of the constructor, which in turn calls the setIsbn method. If you know that such methods 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.

Inheritance

As mentioned a couple of times, it’s possible to create classes that extend to other classes. This is commonly known as inheritance. It means that the new class inherits all the properties and methods of another class.

Invoking Parent Constructors

PHP does not automatically call the parent constructor; you must call it explicitly using the parent keyword as well as the scope resolution operator (::) . This is different from calling other methods defined on the object or any parent where the -> operator is used. An example follows:
<?php
    class Employee
    {
        protected $name;
        protected $title;
        function __construct()
        {
            echo "Employee constructor called! ";
        }
    }
    class Manager extends Employee
    {
        function __construct()
        {
            parent::__construct();
            echo "Manager constructor called!";
        }
    }
    $employee = new Manager();
?>
This results in the following:
Employee 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!

Destructors

Just as you can use constructors to customize the object creation process, so can you use destructors to modify the object destruction process. 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 "Book class instance created. ";
        }
        function __destruct()
        {
            echo "Book class instance destroyed.";
        }
    }
    $book = new Book("0615303889");
?>
Here’s the result:
Book class instance created.Book class instance destroyed.

Even though the destructor is not called directly by the script, it is called when the script ends and PHP is freeing up the memory used by the objects.

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 is 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. Destructors that are called after the script ends (also called request shutdown) will not be called in any specific order , and if the script is terminated due to a fatal error, the destructor might not be called.

Type Hinting

Type hinting is a feature introduced in PHP 5 and was renamed to type declaration in PHP 7. Type declaration ensures that the object being passed to the method is indeed a member of the expected class or a variable is of a specific type. For example, it makes sense that only objects of class Employee should be passed to the takeLunchbreak() method . Therefore, you can preface the method definition’s sole input parameter $employee with Employee, enforcing this rule. An example follows:
private function takeLunchbreak(Employee $employee)
{
    ...
}

Although type declarations were implemented to work only for objects and arrays in PHP 5, the feature was later expanded to cover scalar types (PHP 7) and iterable (PHP 7.1) types. The type declaration feature only works when parameters are passed to functions/methods. It is possible to assign variables of other types inside the function/method.

Static Class Members

Sometimes it’s useful to create properties 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 is instantiated, so you would set the property to be of the static scope, like so:
<?php
    class Visitor
    {
        private static $visitors = 0;
        function __construct()
        {
            self::$visitors++;
        }
        static function getVisitors()
        {
            return self::$visitors;
        }
    }
    // Instantiate the Visitor class.
    $visits = new Visitor();
    echo Visitor::getVisitors()."<br />";
    // Instantiate another Visitor class.
    $visits2 = new Visitor();
    echo Visitor::getVisitors()."<br />";
?>
The results are as follows:
1
2

Because the $visitors property 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 properties and methods are referred to using the self keyword, sope resolution operator (::) and class name, rather than via $this and arrow operators. This is because referring to static properties 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 property declared as static.

The instanceof Keyword

The instanceof keyword helps you to determine whether an object is an instance of a class, is a subclass of a class, or implements a particular interface (see Chapter 6), and does something accordingly. For example, suppose you want to learn whether $manager is derived from the class Employee:
$manager = new Employee();
...
if ($manager instanceof Employee) echo "Yes";

Note that the class name is not surrounded by any sort of delimiters (quotes). Including them will result in a syntax error. 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 you manage and use class libraries. A few of the more commonly used functions are introduced in this section.

Determining Whether a Class Exists

The class_exists() function returns TRUE if the class specified by class_name exists within the currently executing script context and returns FALSE otherwise. Its prototype follows:
boolean class_exists(string class_name)

Determining Object Context

The get_class() function returns the name of the class to which object belongs and returns FALSE if object is not an object. Its prototype follows:
string get_class(object object)

Learning About Class Methods

The get_class_methods() function returns an array containing method names defined by the class class_name (which can be identified either by the class name or by passing in an object). The list of names depends on the scope the function is called in. If the function is called from outside of the class scope, the function will return a list of all public methods defined in the class or any of the parent classes. If it’s called inside a method on the object (passing in $this as the argument), it will return a list of public or protected methods from any parent classes and all methods from the class itself. Its prototype follows:
array get_class_methods(mixed class_name)

Learning About Class Properties

The get_class_vars() function returns an associative array containing the names of all properties and their corresponding values defined within the class specified by class_name. The list of returned property names follows the same pattern as described above for methods. Its prototype follows:
array get_class_vars(string class_name)

Learning About Declared Classes

The function get_declared_classes() returns an array containing the names of all classes defined within the currently executing script, including any standard class defined by PHP and any extension loaded. 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 134 classes. Its prototype follows:
array get_declared_classes(void)

Learning About Object Properties

The function get_object_vars() returns an associative array containing the available non-static properties available to objects restricted by scope and their corresponding values. Those properties that don’t possess a value will be assigned NULL within the associative array. Its prototype follows:
array get_object_vars(object object)
Casting the object to an array or using the print_r() or var_dump() functions will make it possible to see/access private properties and their values.

Determining an Object’s Parent Class

The get_parent_class() function returns the name of the parent of the class to which the object belongs. If object’s class is a base class, that class name will be returned. Its prototype follows:
string get_parent_class(mixed object)

Determining Object Type

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. Its prototype follows:
boolean is_a(object object, string class_name)

Determining Object Subclass Type

The is_subclass_of() function returns TRUE if object (which can be passed in as type string or object) belongs to a class inherited from class_name and returns FALSE otherwise. Its prototype follows:
boolean is_subclass_of(mixed object, string class_name)

Determining Method Existence

The method_exists() function returns TRUE if a method named method_name is available to object and returns FALSE otherwise. Its prototype follows:
boolean method_exists(object object, string method_name)

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 calls 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, PHP has the concept of autoloading objects. 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. 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 a 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 were introduced in Chapter 3.

Traits

One of the great additions to PHP 5.4 was the implementation of traits.

Traits are a way to implement code reuse where multiple classes implement the same functionality. Instead of writing the same code over and over, it can be defined as a trait and “included” in multiple class definitions. The implementation works as a copy and paste at compile time. If it’s necessary to change the implementation, it can be done in a single place, the definition of the trait, and it will take effect every place where it’s used.

Traits are defined in a similar way to classes but use the keyword trait instead of class. They can contain both properties and methods but can’t be instantiated to objects. A trait can be included in a class by the statement use <trait name>;, and it is possible to include more than one trait in each class by adding each trait as a comma-separated list as use <trait1>, <trait2>;.
<?php
trait Log {
    function writeLog($message) {
        file_put_contents("log.txt", $message . " ", FILE_APPEND);
    }
}
class A {
    function __construct() {
        $this->WriteLog("Constructor A called");
    }
    use Log;
}
class B {
    function __construct() {
        $this->WriteLog("Constructor B called");
    }
    use Log;
}

Properties or methods defined in a trait will overwrite properties or methods with the same name inherited from parent classes and properties, and methods defined in a trait can be overwritten in the class that uses the trait.

Traits are used, in part, to solve the limitation of single inheritance that exists in PHP.

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 were made available with the PHP 5 release.

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

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.19.27.178