Beruflich Dokumente
Kultur Dokumente
448191 - PHPFreaks.com
-1-
448191 - PHPFreaks.com
Introduction
Welcome to part one of the "Application Design" series. This series intends to show you how to create extensible applications with reusable code. In this first part you will be introduced to OOP in PHP. This article is an overview of what PHP has to offer with respect to OOP, with examples on how to use these concepts. If you have wanted to grasp OOP, but haven't come around to learning it, this article is for you. If you've read some "Hello World" in OOP tutorial, gotten familiar with OO syntax but are interested in learning more, this article is for you too. PHP 5 has been released for quite some time, putting more stress on Object Orientated development for PHP. PHP 5 comes with a new object model, a lot faster and adding a lot of new features. There are workarounds to mimic some of these features in PHP 4, some of which are covered in this article. Nevertheless, the main focus is on PHP5.
Prerequisites
Knowledge of PHP and PHP syntax at an intermediate level is assumed.
-2-
448191 - PHPFreaks.com
Index
Index ................................................................................................................. 3 Prerequisites ....................................................................................................... 2 Introduction ........................................................................................................ 2 1. General PHP OOP and Syntax ............................................................................. 4 1.1 Classes ....................................................................................................... 5 1.2 Inheritance ................................................................................................. 6 1.3 Constructors................................................................................................ 7 1.4 Scope Resolution Operator ............................................................................ 8 1.5 Abstract Classes ........................................................................................ 11 1.6 Magic Methods........................................................................................... 12 2. PHP 5 ........................................................................................................... 13 2.1 Object Handles .......................................................................................... 13 2.2 Interfaces ................................................................................................. 13 2.3 Autoload ................................................................................................... 14 2.4 Destructors ............................................................................................... 15 2.5 Visibility.................................................................................................... 15 2.6 Class Constants ......................................................................................... 16 2.7 Type Hinting.............................................................................................. 17 2.8 Exceptions ................................................................................................ 18 2.9 The Final Keyword...................................................................................... 19 2.10 More Magic Methods ................................................................................. 19 2.10.1 Object Overloading ............................................................................. 19 2.10.2 Object cloning .................................................................................... 20 2.10.3 Other ................................................................................................ 22 2.11 Object Iteration ....................................................................................... 23 3. Applying OOP Principles ................................................................................... 25 In conclusion ..................................................................................................... 28
-3-
448191 - PHPFreaks.com
$someVariable = &new SomeClassDefiningAnObject; Note: PHP 4 requires that you use return by reference (&) to avoid multiple copies of the object. In PHP 5, this has been eliminated, see section 2.1 Object Handles. Executing an embedded function (method):
$returnValue = $someVariable->someMethodThatReturnsSomething();
-4-
448191 - PHPFreaks.com
$someVariable->someProperty = 'SomeValue'; $currentValue = $someVariable->someProperty; Ok, now you should have a basic understanding of what objects are and how to operate on them. Next were looking at defining the state and behaviour of objects: classes.
1.1 Classes
You pretty much already know what classes are: the definition of an object. Also referred to as a stateless object or object blueprint, the class defines how the object will look after first instantiation, and how it will behave in response to operating on it. However it also possible to operate within the scope of a class without an instantiation. You will read more about that in the Scope Resolution Operator section. Consider this extremely simple example of a class:
//PHP4 class Dog { var $hungry = 'hell yeah.'; function eat($food){ $this->hungry = 'not so much.'; } } $this is a reserved variable name, referring to the current instantiation of the object. By instantiating, we create a new Dog.
$dog = &new Dog The initial state of this dog is that it is pretty hungry.
echo $dog->hungry; Echoes: hell yeah. So we feed our newly instantiated dog a treat, to modify its state.
$dog->eat('cookie');
-5-
448191 - PHPFreaks.com
echo $dog->hungry; Will echo: not so much. Doggie is happy enough, moving on.
1.2 Inheritance
Classes can have parent and child classes. When an object is instantiated by name of a child class, PHP looks for parent classes and starts combining the declarations, from the top, to create the initial object. This is called inheritance. It isnt such a hard concept to grasp: a child inherits anything from its parents and ancestors that isnt redefined on the way down. If a class lower in the chain has a property or method with the same name as one higher in the chain, the last declaration is used for requests to the object. The way PHP is informed that a class has a parent class is with the extends keyword. Like with most popular languages, in PHP one class can only extend a single other class. An infinite number of classes can be derived from (extending) a single class though. A simple example:
//PHP4 class Animal { var $hungry = 'hell yeah.'; function eat($food){ $this->hungry = 'not so much.'; } } class Dog extends Animal { function eat($food){ if($food == 'cookie'){ $this->hungry = 'not so much.'; } else { echo 'barf, I only like cookies!'; } } } Method eat is overwritten, because doggie only likes cookies. On the other hand, because all animals are hungry when you dont feed them, the initial state of $hungry need not be defined in Dog. The fictional Bird, Cat and Piggy could all extend Animal. Class Animal is unaware of the fact that it is being extended; there are no references to Dog whatsoever. Say Animal extended another class called LifeForm, and I instantiated Animal, only methods and properties of Animal and LifeForm would be included in the object.
-6-
448191 - PHPFreaks.com
1.3 Constructors
Constructors are a way to define the default behaviour (set the default state) upon instantiation. You can, as shown in the previous example, define the default state by setting default values for properties. A constructor is nothing more than a method that is executed when instantiating an object. This is referred to as initializing the object. An object isnt fully initialized, constructed, until the constructor method has completed (if present). A constructor method isnt required, our previous examples worked just fine without them. Another thing that should be noted is that only the constructor of the class used to instantiate is called automatically, any parent constructors need to be called explicitly. PHP 4 and 5 use different naming for constructors. PHP 4 will look for a method with the same name as the class, PHP 5 uses the __construct magic method. The PHP 4 method works in PHP 5 too, for backwards compatibility.
//PHP4 class Dog extends Animal { var $breed; function Dog($breed){ $this->breed = $breed; } function eat($food){ if($food == 'cookie'){ $this->hungry = 'not so much.'; } else { echo 'barf, I only like cookies!'; } } } Instantiating a Dog requires us to specify its breed. The property breed is assigned a new value by cause of this initialization (previously NULL), and we have a Dog which initial state specifies its breed:
$dog = &new Dog('Golden Retriever'); We could change its breed afterwards if wed like:
$dog->breed = 'Bloodhound';
-7-
448191 - PHPFreaks.com
//PHP4 class Animal { var $hungry = 'hell yeah.'; function Animal(){ echo 'I am an animal.'; } function eat($food){ $this->hungry = 'not so much.'; } } class Dog extends Animal { var $breed; function Dog($breed){ $this->breed = $breed; Animal::Animal(); } function eat($food){ if($food == 'cookie'){ Animal::eat($food); } else { echo 'barf, I only like cookies!'; } } } $dog = new Dog('Rotweiler'); $dog->eat('cookie'); echo $dog->hungry; Dog is using its parents method eat to refer to the declaration of eat that was overwritten by its own declaration of eat. You need not specify the specific class name like in the above example to refer to the last declaration of a method (or property), the parent keyword will point to that reference:
parent::eat($food);
-8-
448191 - PHPFreaks.com
Should you have multiple levels of inheritance, and want to address a declaration other than the one last defined, youll have to specify the class like in the above example class. The constructor of parent classes isnt called upon instantiation, so if we desire to run a parent constructor, we have to call it explicitly:
Animal::Animal(); Trying to call a method statically which has references to object specific variables (makes use of $this) from outside of the object, will throw an error:
Dog::eat('cookie'); Result: Fatal error: Using $this when not in object context PHP 5 introduces static class members. If you are unfamiliar with static variables, have a thorough read on Variable Scope in the manual. Because all examples so far have been in PHP 4, Ill first show you a neat trick to mimic static class member behaviour in PHP 4.
//PHP4 class Dog{ function &staticHungry($value = null){ static $hungry; if($hungry === null){ //$hungry not initialized yet, do so now. $hungry = 'hell yeah.'; } elseif($value !== null) { $hungry = $value; } return $hungry; } } //Echo initial value: echo Dog::staticHungry(); echo '<br />'; //Set new value and echo it: echo Dog::staticHungry('not so much.'); Its rather simple, actually. We make use of the fact that PHP 4 does allow static variables in the function scope, and wrap a method around a static variable to allow setting and fetching of the value. Its patchy, but it works. Luckily, PHP 5 features static class members. In strict error mode (in PHP6 this is included in E_ALL) it also requires you to define what methods can be used statically.
-9-
448191 - PHPFreaks.com
//PHP5 class Dog{ static $hungry = 'hell yeah.'; static function eat($food){ if($food == 'cookie'){ self::$hungry = 'not so much.'; } else { echo 'barf, I only like cookies!'; } } } Dog::eat('cookie'); echo Dog::$hungry; Note the self keyword. It is simply referring to this class declaration. Like with the parent keyword, alternatively one could use the actual name of the class (Dog). In part three of this series youll find a very useful pattern making use of static class members, the Singleton pattern. Were still a mile away from that, so lets move on.
- 10 -
448191 - PHPFreaks.com
//PHP5 abstract class Animal { public $hungry = 'hell yeah.'; abstract public function eat($food); } class Dog extends Animal{ function eat($food){ if($food == 'cookie'){ $this->hungry = 'not so much.'; } else { echo 'barf, I only like cookies!'; } } } $dog = new Dog(); echo $dog->hungry; //echoes "hell yeah." $dog->eat('peanut'); //echoes "barf, I only like cookies!" Never mind the public keyword for now. This might seem like strictly a PHP 5 thing, but abstract classes can easily be created in PHP 4 also. A simplified example:
//PHP4 class Animal { var $hungry = 'hell yeah.'; function Animal(){ trigger_error('"Animal" is an abstract class.',E_USER_ERROR); } function eat($food){ trigger_error('Abstract method "eat" not implemented.',E_USER_ERROR ); } }
- 11 -
448191 - PHPFreaks.com
- 12 -
448191 - PHPFreaks.com
2. PHP 5
By now you know that PHP 5 has many features PHP 4 lacks, it this chapter Ill go into those features. If you have no interest in PHP 5 (how can you not!) you can skip this chapter.
2.2 Interfaces
PHP 5 features interfaces. Not to be confused with interfaces in the more general sense, the interface keyword creates an entity that can be used to enforce a common interface upon classes without having to extend them like with abstract classes. Instead an interface is implemented. Interfaces are a lot different from abstract classes. For one, theyre not actually classes. They dont define properties, and they dont define any behaviour. The methods declared in an interface must be declared in classes that implement it. Because an interface in the more general sense is a definition of how an object interacts with other code, all methods must be declared public (see section on visibility in this chapter). An abstract method can have any visibility, but the extending classes must have their implementations use the same (or weaker) visibility. Implementing an interface adds the methods as abstract methods to the subject class, failure to implement it will result in an error like the following: Fatal error: Class SomeConcreteClass contains n abstract method(s) and must therefore be declared abstract or implement the remaining methods Yes, abstract classes can implement interfaces. Interfaces can be looked upon as a contract, a certificate of compliance if you will. Other code is guaranteed that a class implementing it will use certain methods to interact. Enough babbling, lets see a code example:
- 13 -
448191 - PHPFreaks.com
//PHP5 interface Animal { public function eat($food); } interface Mammal { public function giveBirth(); } class Dog implements Animal, Mammal{ public $gender = 'male'; function eat($food){ if($food == 'cookie'){ $this->hungry = 'not so much.'; } else { echo 'barf, I only like cookies!'; } } function giveBirth(){ if($this->gender == 'male'){ echo 'I can\'t, I am a boy :P'; } else { echo 'I\'m not even pregnant yet.'; } } } Doggie implements 2 interfaces, both Animal and Mammal. You can implement as many interfaces as you like.
2.3 Autoload
A very convenient feature, __autoload allows you to get rid of all those annoying includes that need to be managed. This magic function will execute whenever a class or interface is referenced that hasnt been defined. That gives you the opportunity to include it. Following a standard class and directory naming scheme, heres a simple example of how that might look:
//PHP5 function __autoload($className) { $file = 'lib/'.$className. '.class.php'; if(!file_exists($file)){ return false; } else { include $file; } } We dont need include_once, because once the file is included, __autoload will not trigger on that class or interface reference again. Note that __autoload can also be confined to the scope of a class or object.
- 14 -
448191 - PHPFreaks.com
2.4 Destructors
Destructors are another type of magic methods. Indicated by __destruct, these methods are called when all references to their objects are removed. This includes explicit un-setting and script shutdown. A quick example of this:
//PHP5 class Example { function __destruct() { echo 'Destructing object.'; } } $objectOne = new Example(); $objectTwo = new Example(); unset($objectOne); echo 'Script still running.' This echoes: Destructing object. Script still running. Destructing object. Object one is destructed when we explicitly unset it, object two just before the script execution is completed. An objects destructor is always executed. Note that if we had created a second object from within class Example, its destructor would also have been executed, as it would have removed all references to the embedded object.
2.5 Visibility
PHP 5 allows you to declare the visibility of methods and properties. There are three types of visibility: public, protected and private. Public Public methods and properties are visible (accessible) to any code that queries them. No accessibility restrictions are applied. In PHP 4 all methods and properties are public. In PHP 5, methods without visibility declaration are assumed public, the visibility declaration is required for object properties (so that excludes static and constant class members). Protected Requests are only allowed from within the objects blueprint (that includes parent and child classes). Meaning the following would fail:
- 15 -
448191 - PHPFreaks.com
//PHP5 class Teeth { protected $colour = 'white'; public function stain(){ $this->colour = 'yellow'; } } class Dog { public $teeth; public function __construct(){ $this->teeth = new Teeth(); } public function eat($food){ if($food == 'cookie'){ $this->hungry = 'not so much.'; //Attempt to turn teeth green: $this->teeth->colour = 'green'; } else { echo 'barf, I only like cookies!'; } } } $dog = new Dog(); Produces: Fatal error: Cannot access protected property Teeth::$colour Should Teeth have been a parent class of Dog instead of a member object (class Dog extends Teeth bad practice), $colour would have been accessible though $this, but also statically by Teeth::$colour (or parent::$colour). Private Access is limited to the defining class (the class used to instantiate). No external access whatsoever is allowed. One thing that should be noted when using protected or private properties, is that if you attempt to assign a value to a property that isnt visible to the class you are doing it in, you will be creating a new property instead of resetting the original. Keep that in mind when you get unexpected values: check the propertys visibility.
- 16 -
448191 - PHPFreaks.com
Class constants are just regular constants, confined to a class declaration. Because constants are unchangeable, they are independent of any state the object could be in. Therefore they can only be called statically.
//PHP5 class Dog { const NUMBER_OF_LEGS = '4'; public function __construct(){ echo 'I have '.self::NUMBER_OF_LEGS.' legs, and you can\'t take that away from me!'; } } $dog = new Dog(); Both $dog->NUMBER_OF_LEGS and $this->NUMBER_OF_LEGS would have PHP looking for a non-existent object property: $NUMBER_OF_LEGS.
//PHP5 class Rabbit { } class Feeder { public function feedRabbit(Rabbit $dog, $food){ $dog->eat($food); } } class Dog { public function eat($food){ if($food == 'cookie'){ $this->hungry = 'not so much.'; } else { echo 'barf, I only like cookies!'; } } } $dog = new Dog(); $feeder = new Feeder(); $feeder->feedRabbit($dog, 'broccoli'); Attempting to use an instance of Dog with the feedRabbit method results in the following error: Fatal error: Argument 1 passed to Feeder::feedRabbit() must be an instance of Rabbit
- 17 -
448191 - PHPFreaks.com
However, type hinting allows a more generic use. Consider the following example:
//PHP5 class Animal { } class Feeder { public function feedAnimal(Animal $animal, $food){ $animal->eat($food); } } class Dog extends Animal { public function eat($food){ if($food == 'cookie'){ $this->hungry = 'not so much.'; } else { echo 'barf, I only like cookies!'; } } } $dog = new Dog(); $feeder = new Feeder(); $feeder->feedAnimal($dog, 'broccoli'); Because $dog is not only a Dog, but also an Animal, the requirement is met. Doggie doesnt like broccoli (who does?), but that is besides the point. Currently PHP only supports type hinting with objects and arrays.
Note: since PHP 5.2, failing type hinting requirements result in a E_RECOVERABLE_ERROR type error, not an immediate fatal error.
2.8 Exceptions
PHP 5 introduces the concept of exceptions to PHP. An exception is not an error, an uncaught exception is (a fatal error). Using exceptions you will need the following keywords: try, throw and catch. PHP 5 has its build-in Exception class, which you can extend, but for this simple example I will stick to using the standard Exception class.
- 18 -
448191 - PHPFreaks.com
try { $statement = 'Doggie likes broccoli.'; echo $statement; if($statement == 'Doggie likes broccoli.'){ throw new Exception('liar!'); } //We escape from the try block as soon as an exception is thrown. echo 'Doggie won\'t speak these words.'; } catch(Exception $e) { echo 'Caught exception of type Exception: "' .$e->getMessage().'". We know doggie only likes cookies.'; } The code in the try block is executed until an exception is thrown. If an exception is thrown, the code in the corresponding catch block is executed. If there isnt a corresponding catch block, the exception is uncaught, resulting in a fatal error.
448191 - PHPFreaks.com
The following example class uses __set to check if an embedded object does have the property requested, before creating a new property for the parent object.
//PHP5 class DomXml { private $domDoc; public function __construct() { $this->domDoc = new DOMDocument(); } private function __set($name,$value){ //Overload. if(property_exists($this->domDoc,$name)){ //Set DOMDocument value. $this->domDoc->$name = $value; } else { //Create new DomXml property. $this->$name = $value; } } } An example __call use:
private function __call($name,$params){ //Overload method call. if(method_exists($this->doc,$name)){ return call_user_func_array( array($this->doc,$name),$params); } else { //Overloading produced unusable result. throw new DomXmlException( 'Call to undeclared method "'.$name.'".'); } } Methods __get, __isset and __unset have similar uses.
$obj = new Example(); $objectCopy = clone $obj; Above gives you a new object that is an exact copy of $obj in the state it was when copied. - 20 -
448191 - PHPFreaks.com
The __clone method is triggered by this clone keyword. This allows you, for example, to ensure embedded objects are also cloned (otherwise they would this use the same object handle for the embedded objects). The following example illustrates this:
//PHP5 class Teeth { public $colour = 'white'; } class Dog { public $teeth; public function __construct(){ $this->teeth = new Teeth(); } } $Lassie = new Dog(); $Snoopy = clone $Lassie; $Snoopy->teeth->colour = 'green'; echo $Snoopy->teeth->colour.'<br/>'; echo $Lassie->teeth->colour.'<br/>'; That will echo: green green Changing the property colour to green on $Snoopys teeth, also changes $Lassies teeth to green, because they share the same teeth. Imagine that, two dogs attached at the mouth To give Lassies clone Snoopy its own set of teeth, we can use the __clone method:
- 21 -
448191 - PHPFreaks.com
/PHP5 class Teeth { public $colour = 'white'; } class Dog { public $teeth; public function __construct(){ $this->teeth = new Teeth(); } public function __clone(){ $this->teeth = clone $this->teeth; } } $Lassie = new Dog(); $Snoopy = clone $Lassie; $Snoopy->teeth->colour = 'green'; echo $Snoopy->teeth->colour.'<br />'; echo $Lassie->teeth->colour.'<br />'; Now it outputs: green white Voila, a cloned Dog now has its own teeth. Keep in mind that at times you may require that two objects do use the same embedded object.
2.10.3 Other
Other methods that dont fit in the previous categories. __toString: Similar to __sleep and __wakeup, this magic method can be used to define how an object will present itself if the whole object is treated as a string. Example:
class Dog{ function __toString(){ return 'I am Dog.'; } } $dog = new Dog(); echo $dog;
- 22 -
448191 - PHPFreaks.com
The Dog object speaks: I am Dog. __set_state: This is a static method that can be used to reinitialize an object after being flattened by var_export.
//PHP4 class Example { var $propertyOne = 'value1'; var $propertyTwo = 'value2'; var $propertyThree = 'value3'; } $example = new Example(); foreach($example as $property=>$value){ echo 'Property "'.$property.'" has a value of "'.$value.'"<br />'; }
Output: Property "propertyOne" has a value of "value1" Property "propertyTwo" has a value of "value2" Property "propertyThree" has a value of "value2" Slightly more complex, on PHP 5 the visibility is taken into account:
- 23 -
448191 - PHPFreaks.com
//PHP5 class ExampleParent { protected $propertyOne = 'value1'; public $propertyTwo = 'value2'; } class Example extends ExampleParent { private $propertyThree = 'value3'; public function __construct(){ foreach($this as $property=>$value){ echo 'Internal iteration of Example: Property "' .$property.'" => "'.$value.'"<br />'; } echo '<br />'; } } $example = new Example(); foreach($example as $property=>$value){ echo 'External iteration of Example: Property "' .$property.'" => "'.$value.'"<br />'; } echo '<br />'; $exampleParent = new ExampleParent(); foreach($exampleParent as $property=>$value){ echo 'External iteration of ExampleParent: Property "' .$property.'" => "'.$value.'"<br />'; }
Output: Internal iteration of Example: Property "propertyThree" => "value3" Internal iteration of Example: Property "propertyOne" => "value1" Internal iteration of Example: Property "propertyTwo" => "value2" External iteration of Example: Property "propertyTwo" => "value2" External iteration of ExampleParent: Property "propertyTwo" => "value2"
- 24 -
448191 - PHPFreaks.com
Remember these classes? //PHP4 class Animal { var $hungry = 'hell yeah.'; function eat($food){ $this->hungry = 'not so much.'; } } class Dog extends Animal { function eat($food){ if($food == 'cookie'){ $this->hungry = 'not so much.'; } else { echo 'barf, I only like cookies!'; } } } I used them to explain the concept of inheritance to you. Class Dog inherits Animals properties and methods when an object is instantiated, if it doesnt re-declare them itself. Animal could be the base class for other animal classes, like Bird and Cat. Subclasses like these would have a common interface defined by Animal. Confused? Sharing an interface simply means other components of your application can interact with the classes in a similar way. This interaction is defined by the calling routines (methods and method arguments). In this ridiculously simply example, eat is the whole of the interface. Any class extending Animal is guaranteed to have a eat method which takes a single argument, because even if they dont declare it themselves, Animal defines the default behaviour! Lets take a look at a possible Bird
- 25 -
448191 - PHPFreaks.com
//PHP4 class Bird extends Animal { function eat($food){ if($food == 'seed'){ $this->hungry = 'not so much.'; } else { echo 'barf, I only like seed!'; } } }
As you can see, Bird isnt all that different from Dog. They both eat food. However, because they are not the same type of Animal, they behave differently in response to the $food they are being fed. This is referred to as having their own implementations of the interface provided by Animal, or simply: implementations of Animal. This is at the core of the principle of polymorphism: Different types of objects can be handled in the same way, even though their implementations vary. Object orientated programming promotes modularity by encapsulation. Encapsulation hides information about one part of your application from other parts. Again, this really comes down to implementing a solid interface. To make your application modular, you will have to protect different parts from depending on specific implementations of other parts. That was a mouth full, but the bottom line is you have to separate the different concepts involved in the processing. This practice is popularly known as separation of concerns. You try not to make a class that has more than one concern, is handling more than one concept. Say I was building a framework, and currently creating a module to handle XML. Id like several convenience methods, depending on the type (implementation) of XML (XHTML, RSS or XSL). I COULD simply add all of these class members related to a certain implementation of XML to one single class. But it could quickly become a very large and hard to manage class. Also, if I decide to add more types of XML as an afterthought, or simply because they werent near the top of the priority list, Id have to go in and edit the code that might influence how the other types are handled. Furthermore, what if I decide to use different parser? Id have to edit virtually every line of code in the class! Instead, lets separate the XML implementation from the method of parsing. One way this could be accomplished is through inheritance, but that could easily create many subclasses. Example with the previously mentioned types of XML plus the handlers DOM and SimpleXML: Xml_Dom Xml_Dom_Xhtml extends Xml_Dom Xml_Dom_Rss extends Xml_Dom Xml_Dom_Xsl extends Xml_Dom Xml_SimpleXML Xml_SimpleXML_Xhtml extends Xml_SimpleXML Xml_SimpleXML_Rss extends Xml_SimpleXML Xml_SimpleXML_Xsl extends Xml_SimpleXML - 26 -
448191 - PHPFreaks.com
Count: 8 classes. Not to mention *_SimpleXML_Xhtml and its siblings perform similar tasks as their *_Dom counterparts, meaning I have to edit two files instead of one if I decide to change how a specific XML implementation is handled. Instead, it is preferable to encapsulate the implementation, and have both methods of parsing follow a common interface. This makes the implementation independent of the method of parsing (the parser extension used). Xml_Document_Dom Xml_Document_SimpleXml Xml_Implementation_Xhtml Xml_Implementation_Rss Xml_Implementation_Xsl
Count: 5 classes. More importantly, if I decide to change how RSS files are handled, I only have to change ONE class. Example client code:
//PHP5 $doc = new Xml_Document_Dom; $doc->setDTDDir('/lib/Xml/dtd'); $doc->loadXml(file_get_contents('test.xml')); $doc->setImplementation(new Xml_Implementation_XHtml('transitional','utf8')); $doc->validate(); $xsldoc = new Xml_Document_SimpleXml; $xsldoc->setDTDDir('/lib/Xml/dtd'); $xsldoc->setImplementation(new Xml_Implementation_Xsl());
The implementation has been encapsulated in a property of the document object, allowing the same implementation classes to be used for different methods of parsing. Also thanks to the fact that Xml_Document_Dom and Xml_Document_SimpleXml have a common interface. This is called decoupling, more about that in part 3.
- 27 -
448191 - PHPFreaks.com
In conclusion
If you were new to OOP, you probably learned a lot reading this article. If you were not, and this is all dull and boring to you, get ready for part 2 and 3, things just might get a little more interesting. :) If you have any comments about the content of this article, you can notify me by emailing johnkleijn at the free email service provided by Google, or send me a PM on the PHPFreaks forums. If you have QUESTIONS related to this article, please post them on the public forums. I hope you enjoyed this one, and will also read part two and three.
- 28 -