PHP

Class Hierarchies

Forunately, I can use inheritance to accomplish these goals; PHP even provides a few extra pieces of functionality to make it easier to use. Instead of having one Product class that knows about a number of sources, I can have a number of classes inheriting from an abstraction of what a product is. Also, each class can handle a different implementation while acting like the class it is abstracting. I will now have three classes, as shown in figure.

Figure My new class hierarchy permitting cleaner separation of code.

People will still be writing code as if they were using Product objects, but the actual underlying object will be one of the LocalProduct or NavigationParternProduct classes. The ability to work with a class as a particular type, even if the underlying classes are of varying subtypes, is often referred to as polymorphism. To declare my Product class as merely containing a template to which its inheriting classes must adhere, I'll prefix its class keyword with the keyword abstract.

<?php
  abstract class Product
  {
    // body goes here.
  }
?>

By adding this new keyword, I have indicated that you cannot create an instance of the Product classyou must instantiate and create an inheriting subclass.

My other requirement was that all of my products had to have the same public interface, or set of publically available methods and properties that it exposes. For my Product class, I want subclasses to provide new implementations for the get_number_in_stock and as the ship_product_units methods.

I could declare these methods on the Product class and leave them without a meaningful implementation in their bodies, but there is an even better solution available to us: I can declare functions as abstract and not even provide a body for them. My Product class will now start to look as follows:

<?php
  abstract class Product
  {
    // etc.
    //
    // subclasses must implement these!
    //
    abstract public function get_number_in_stock($in_num_desired);
    abstract public function ship_product_units($in_num_shipped);
    // etc.
  }
?>

If you declare a class as abstract, then you cannot create new instances of it, and will only be allowed to use the new operator on subclasses of this class. If you declare any functions in your class as abstract, then the class must also be declared as abstract; otherwise, PHP will give you an error message:

<?php
  class TestClass
  {
    abstract public function iamabstract();
  }
?>
Fatal error: Class TestClass contains 1 abstract methods and must
  therefore be declared abstract (ABC::iamabstract) in
  /home/httpd/wwwphpwebapps/src/abstract.php on line 8

My two new classes, LocalProduct and NavigationPartnerProduct, will not contain very much. They will both inherit directly from Product and will override and reimplement the two key methods mentioned earlier to do their work. You implement a method in your new subclass declared as abstract in your base class by declaring and implementing the method without the abstract keyword. My three classes will look as shown in Listing 1

Listing 1. My Class Hierarchy for Products
<?php
  abstract class Product
  {
    protected $id;
    protected $name;
    protected $desc;
    protected $price_per_unit;
    public function __construct
    (
      $in_prodid,
      $in_prodname,
      $in_proddesc,
      $in_price_pu
    )
    {
      $this->id = $in_prodid;
      $this->name = $in_prodname;
      $this->desc = $in_proddesc;
      $this->price_per_unit = $in_price_pu;
    }
    public function __destruct()
    {
    }
    //
    // subclasses must implement these!
    //
    abstract public function get_number_in_stock($in_num_desired);
    abstract public function ship_product_units($in_num_shipped);
    public function get_ProductID()
    {
      return $this->pid;
    }
    public function get_Name()
    {
      return $this->name;
    }
    public function get_Description()
    {
      return $this->desc;
    }
    public function get_PricePerUnit()
    {
      return $this->price_per_unit;
    }
  }
  class LocalProduct extends Product
  {
    public function get_number_in_stock($in_num_desired)
    {
      // go to my local dbs and see how many I have left.
      // return -1 on a failure of some sort.
    }
    public function ship_product_units($in_num_shipped)
    {
      // go to my local dbs and mark $in_number units as no
      // longer available.  TRUE == success, FALSE == failure.
    }
  }
  class NavigationPartnerProduct extends Product
  {
    public function get_number_in_stock($in_num_desired)
    {
      // go to my navigation equipment partner's servers
      // and see how many are left.  return -1 on failure.
    }
    public function ship_product_units($in_num_shipped)
    {
      // go to my navigation equipment partner's servers
      // and mark $in_number units as no longer available.
      // Return FALSE on failure, TRUE on success.
    }
  }
?>

My Product class still contains some implementation I would like to share with subclassesit has a number of member variables that contain data about the product, and there is no reason to waste them (although subclasses should be allowed to override some if they wish), or the methods to get at them. However, you will have noticed that I no longer need the $location member variable anymore since the subclasses naturally know where to get the product and worry about all the possibilities.

Also, you will have noticed that I do not need to define a new constructor in either of those classes since the constructor for my base class is sufficient for my inheriting classes. PHP will make sure that the programmer passes in five parameters to the constructor when creating instances of these types.

The nice thing about my hierarchy is that once the objects are created, I do not care about their actual typethey all look and behave just like the Product class. When I call either of the get_number_in_stock or ship_product_units methods, I are assured that the correct one will be executed for the appropriate object.

by BrainBellupdated
Advertisement: