Introduction To Object-Oriented Programming With PHP: Marcus Börger
Introduction To Object-Oriented Programming With PHP: Marcus Börger
Marcus Brger
Overview
; ; ; ; ; ; What is OOP? PHP and OOP Exceptions Iterators Reflection Patterns
Marcus Brger
What is OOP
class Useless extends Nonsense { abstract function blaBla(); }
Marcus Brger
Marcus Brger
Inheritance
Polymorphism
Marcus Brger
Encapsulation
; Encapsulation is about grouping of functionality (operations) and related data (attributes) together into a coherent data structure (classes).
Marcus Brger
Encapsulation
; Encapsulation is about grouping of functionality (operations) and related data (attributes) together into a coherent data structure (classes). Classes represent complex data types and the operations that act on them. An object is a particular instance of a class.
Marcus Brger
Encapsulation
; Encapsulation is about grouping of functionality (operations) and related data (attributes) together into a coherent data structure (classes). Classes represent complex data types and the operations that act on them. An object is a particular instance of a class. The basic idea is to re-code real life.
For instance, if you press a key on your laptop keyboard you do not know what is happening in detail. For you it is the same as if you press the keyboard of an ATM. We say the interface is the same. If another person has the same laptop the internal details would be exactly the same.
Marcus Brger
Encapsulation
; Encapsulation is about grouping of functionality (operations) and related data (attributes) together into a coherent data structure (classes). Classes represent complex data types and the operations that act on them. An object is a particular instance of a class. The basic idea is to re-code real life.
For instance, if you publish a text that is not really different from publishing a picture. Both are content types and you might want to encapsulate the details on how to do the actual publishing in a class. And once you have that you can easily have content that consists of both pictures and text and yet use the same operations for publishing. Then later you might publish tables using the same interface.
Marcus Brger Introduction to Object-oriented programming with PHP 9
Data Hiding
; Another difference between objects and arrays is that objects permit strict visibility semantics. Data hiding eases refactoring by controlling what other parties can access in your code.
; ; ; ; ; public protected private final abstract anyone can access it only descendants can access it only you can access it no one can re-declare it someone else will implement this
Inheritance
; Inheritance allows a class to specialize (or extend) another class and inherit all its methods, properties and behaviors. This promotes
; ; ; ; ; Extensibility Reusability Code Consolidation Abstraction Responsibility
Marcus Brger
12
Marcus Brger
13
But its hard to keep base_to_xml() working for the disparate foo and bar types.
Marcus Brger
14
class Bar extends Base { public function toXML() { parent::toXML(); // bar specific stuff } }
15
Polymorphism?
; Suppose a calendar that is a collection of entries.
Procedurally dislpaying all the entries might look like: foreach($entries as $entry) { switch($entry[type]) { case 'professional': display_professional_entry($entry); break; case 'personal': display_personal_entry($entry); break; } }
Marcus Brger
16
The key point is we don't have to modify this loop to add new types. When we add a new type, that type gets a display() method so that it knows how to display itself, and were done. Also this is much faster because we do not have to check the type for every element.
Marcus Brger Introduction to Object-oriented programming with PHP 17
A class can have a __toString() method which defines how its objects are converted into a textual representation. PHP 5.2 supports this in all string contexts.
Marcus Brger
18
Unlike other languages PHP does not and will not offer polymorphism for method calling. Thus the following will never be available in PHP <?php class Test { function toXML(Personal $obj) // function toXML(Professional $obj) // } ?> To work around this
; Use the other way round (call other methods from a single toXML() function in a polymorphic way) ; Use switch/case (though this is not the OO way)
Marcus Brger
19
Another example
class Humans { public function /*...*/ } public function public function public function public function } __construct($name) {
Marcus Brger
20
Some Inheritance
class Humans { public function public function public function public function public function } class Women extends public function } __construct($name) { /*...*/ } eat() { /*...*/ } sleep() { /*...*/ } snore() { /*...*/ } wakeup() { /*...*/ } Humans { giveBirth() { /*...*/ }
Marcus Brger
21
Inheritance+Polymorphism
class Humans { public function __construct($name) { /*...*/ } public function eat() { /*...*/ } public function sleep() { /*...*/ } public function wakeup() { /*...*/ } } class Women extends Humans { public function giveBirth() { /*...*/ } } class Men extends Humans { public function snore() { /*...*/ } }
Marcus Brger
22
A little abstraction
abstract class Humans { public function __construct($name) { /*...*/ } abstract public function gender(); public function eat() { /*...*/ } public function sleep() { /*...*/ } public function wakeup() { /*...*/ } } class Women extends Humans { public function gender() { return 'female'; } public function giveBirth() { /*...*/ } } class Men extends Humans { public function gender() { return 'male'; } public function snore() { /*...*/ } }
Marcus Brger
23
A little abstraction
abstract class Humans { public function __construct($name) { /*...*/ } abstract public function gender(); public function eat() { /*...*/ } public function sleep() { /*...*/ } public function wakeup() { /*...*/ } } class Women extends Humans { final public function gender() { return 'f'; } public function giveBirth() { /*...*/ } } class Men extends Humans { final public function gender() { return 'm'; } public function snore() { /*...*/ } }
Marcus Brger
24
Marcus Brger
25
; Properties
: No static properties : No constants
; Inheritance
: No abstract, final inheritance, no interfaces : No prototype checking, no types
; Object handling
: Copied by value : No destructors
Marcus Brger
26
Marcus Brger
27
Marcus Brger
28
Marcus Brger
29
Marcus Brger
30
Marcus Brger
32
Instance 1 $prop
Instance 2 $prop
Marcus Brger
33
Static members
; Static methods and properties
; Bound to the class not to the object
; Only exists once per class rather than per instance
; Can be initialized class Object { var $prop; static $stat = "Hello\n"; static function test() { echo self::$stat; } } Object::test(); $obj1 = new Object; $obj2 = new Object;
Marcus Brger
$obj1
$obj2
Instance 1 $prop
Instance 2 $prop
34
Pseudo constants
; ; ; ; ; __CLASS__ __METHOD__ self parent $this shows the current class name shows class and method or function references the class itself references the parent class references the object itself
class Base { static function Show() { echo __FILE__.'('.__LINE__.'):'.__METHOD__."\n"; } } class Object extends Base { static function Use() { Self::Show(); Parent::Show(); } static function Show() { echo __FILE__.'('.__LINE__.'):'.__METHOD__."\n"; } }
Marcus Brger Introduction to Object-oriented programming with PHP 35
Visibility
; Controlling member visibility / Information hiding
; A derived class doesn't know parents private members ; An inherited protected member can be made public
class Base { public $a; protected $b; private $c; } class Derived extends Base { public $a; public $b; private $c; }
Marcus Brger
36
Constructor visibility
; A protected constructor prevents instantiation
class Base { protected function __construct() { } } class Derived extends Base { // constructor is still protected static function getBase() { return new Base; // Factory pattern } } class Three extends Derived { public function __construct() { } }
Marcus Brger Introduction to Object-oriented programming with PHP 37
Constants
; ; Constants are read only static properties Constants are always public
class Base { const greeting = "Hello\n"; } class Dervied extends Base { const greeting = "Hello World\n"; static function func() { echo parent::greeting; } } echo Base::greeting; echo Derived::greeting; Derived::func();
Marcus Brger Introduction to Object-oriented programming with PHP 39
Abstract members
; Methods can be abstract
; They dont have a body ; A class with an abstract method must be abstract
; ;
Marcus Brger
40
Final members
; Methods can be final
; They cannot be overwritten ; They are class invariants
Marcus Brger
41
Often different objects have the same interface without having the same base class
class Line { function draw() {}; } class Polygon { protected $lines; function draw() { foreach($this->lines as $line) $line->draw(); } } class Rectangle extends Polygon { } class Ellipse { function draw() {}; } class Circle extends Ellipse { function draw() { parent::draw(); } }
Ellipse
Circle
Rectangle
Marcus Brger
42
Interfaces
; ; Interfaces describe an abstract class protocol Classes may inherit multiple Interfaces
interface Drawable { function draw(); } class Line implements Drawable { function draw() {}; } class Polygon implements Drawable { protected $lines; function draw() { foreach($this->lines as $line) $line->draw(); } } class Rectangle extends Polygon { } class Ellipse implements Drawable { function draw() {}; } class Circle extends Ellipse { function draw() { parent::draw(); } }
Drawable
Ellipse
Circle
Rectangle
Marcus Brger
43
Property kinds
; Declared properties
; May have a default value ; Can have selected visibility
Virtual properties
; Handled by interceptor methods
Static properties
; Bound to the class rather than to the instance
Marcus Brger
44
Marcus Brger
45
Interceptors
; Allow to dynamically handle non class members
; Lazy initialization of properties ; Simulating Object aggregation and Multiple inheritance
class Object { protected $virtual = array(); function __get($name) { return @$this->virtual[$name]; } function __set($name, $value) { $this->virtual[$name] = $value; } function __unset($name) { unset($this->virtual[$name]); } function __isset($name) { return isset($this->virtual[$name]); } function __call($func, $params) { echo 'Could not call ' . __CLASS__ . '::' . $func . "\n"; } }
Marcus Brger Introduction to Object-oriented programming with PHP 46
Typehinting
; PHP 5 allows to easily force a type of a parameter
; ; ; ; PHP does not allow NULL for typehints Typehints must be inherited as given in base class PHP 5.1 offers typehinting with arrays PHP 5.2 offers optional typehinted parameters (= NULL)
class Object { public function compare(Object $other) { // Some code here } public function compare2($other) { if (is_null($other) || $other instanceof Object) { // Some code here } } }
Marcus Brger
47
Class Design
; ; ; It is important to think about your class hierarchy Avoid very deep or broad inheritance graphs PHP only supports is-a and has-a relations
Bicycle Tires Vehicle Bus Truck Tank
Marcus Brger
Car
Marcus Brger
49
Marcus Brger
50
: Additional user space code 1 Only one single loader model is possible
Marcus Brger
51
Marcus Brger
52
; ;
Ability to register multiple user defined loaders Overwrites ZEND engine's __autoload() cache
; You need to register __autoload if using spl's autoload
<?php spl_autoload_register('spl_autoload'); if (function_exists('__autoload')) { spl_autoload_register('__autoload'); } ?>
Marcus Brger Introduction to Object-oriented programming with PHP 53
; ; ; ; ;
Exceptions
Marcus Brger
55
Exceptions
; Respect these rules
1. Exceptions are exceptions 2. Never use exceptions for control flow 3. Never ever use exceptions for parameter passing
<?php try { // your code throw new Exception(); } catch (Exception $e) { // exception handling } ?>
Marcus Brger Introduction to Object-oriented programming with PHP 56
Exception specialization
; ; Exceptions should be specialized Exceptions should inherit built in class exception
class YourException extends Exception { } try { // your code throw new YourException(); } catch (YourException $e) { // exception handling } catch (Exception $e) { // exception handling }
Marcus Brger Introduction to Object-oriented programming with PHP 57
Exception specialization
; ; Exception blocks can be nested Exceptions can be re thrown
class YourException extends Exception { } try { try { // your code throw new YourException(); } catch (YourException $e) { // exception handling throw $e; } catch (Exception $e) { // exception handling } } catch (YourException $e) { // exception handling }
Marcus Brger
58
Marcus Brger
59
Constructor failure
; ; In PHP 4.4 you would simply unset($this) Provide an argument to receive the error condition
<?php class Object { function __construct( & $failure) // "Object" in PHP 4 { $failure = true; } } $error = false; $o = new Object($error); if (!$error) { // error handling, NOTE: the object was constructed unset($o); } ?>
Marcus Brger Introduction to Object-oriented programming with PHP 60
Constructor failure
; ; In 5 constructors do not return the created object Exceptions allow to handle failed constructors
<?php class Object { function __construct() { throw new Exception; } } try { $o = new Object; } catch (Exception $e) { echo "Object could not be instantiated\n"; } ?>
Marcus Brger Introduction to Object-oriented programming with PHP 61
Marcus Brger
63
SPL Exceptions
; ; SPL provides a standard set of exceptions Class Exception must be the root of all exceptions
Marcus Brger
66
General distinguishing
; LogicException Anything that could have been detected at compile time, during application design or by the good old technology: "look closely" ; RuntimeException Anything that is unexpected during runtime Base Exception for all database extensions
Marcus Brger
67
LogicException
; ; ; ; ;
Value not in allowed domain Argument not valid Length exceeded Some index is out of range
Marcus Brger Introduction to Object-oriented programming with PHP 68
RunTimeException
; ; ; ; ;
An actual value is out of bounds Buffer or other overflow situation Value outside expected range Buffer or other underflow situation Any other unexpected values
Marcus Brger Introduction to Object-oriented programming with PHP 69
Overloading __call
; If using __call, ensure only valid calls are made
abstract class MyIteratorWrapper implements Iterator { function __construct(Iterator $it) { Compile-Time: $this->it = $it; } Error in design function __call($func, $args) { $callee = array($this->it, $func); if (!is_callable($callee)) { throw new BadMethodCallException(); } return call_user_func_array($callee, $args); } }
Marcus Brger
70
Marcus Brger
71
{ { { { {
Marcus Brger
73
Marcus Brger
74
; ; ;
Marcus Brger
75
Reflection
Marcus Brger
77
Reflection API
; Can reflect nearly all aspects of your PHP code
; Functions ; Classes, Methods, Properties ; Extensions
class Foo { public $prop; function Func($name) { echo "Hello $name"; } } ReflectionClass::export('Foo'); ReflectionObject::export(new Foo); ReflectionMethod::export('Foo', 'func'); ReflectionProperty::export('Foo', 'prop'); ReflectionExtension::export('standard');
Marcus Brger
78
Built-in Interfaces
Marcus Brger
80
Built-in Interfaces
; PHP 5 contains built-in interfaces that allow you to change the way the engine treats objects.
; ArrayAccess ; Iterator ; IteratorAggregate
ArrayAccess
; ; Allows for creating objects that can be transparently accessed by array syntax. When combined with the iterator interface, it allows for creating arrays with special properties.
interface ArrayAccess { // @return whether $offset is valid (true/false) function offsetExists($offset); // @return the value associated with $offset function offsetGet($offset); // associate $value with $offset (store the data) function offsetSet($offset, $value); // unset the data associated with $offset function offsetUnset($offset); }
Marcus Brger Introduction to Object-oriented programming with PHP 82
ArrayAccess
; ArrayAccess does not allow references (the following is an error)
class MyArray extends ArrayAccess { function &offsetGet($offset) { /* ... */ } function offsetSet($offset, &$value) { /* ... */ } function offsetExists($offset) { /* ... */ } function offsetUnset($offset) { /* ... */ } }
Marcus Brger
83
ArrayAccess Example
; ; We want to create variables which can be shared between processes. We will set up interception so that access attempts on the variable are actually performed through a DBM file.
Marcus Brger
84
A Trivial Example
<?php if (!class_exists('DbaReader', false)) { require_once dbadeader.inc; } $_SHARED = new DbaReader('/tmp/.counter', 'flatfile'); $_SHARED['counter'] += 1; printf("PID: %d\nCOUNTER: %d\n", getmypid(), $_SHARED['counter']); ?>
Marcus Brger
86
Iterators
; ; Normal objects behave like arrays when used with the foreach construct Specialized Iterator objects can be iterated differently
<?php class Object { public $prop1 = "Hello "; public $prop2 = "World\n"; } foreach(new Object as $prop) { echo $prop; } ?>
Marcus Brger
87
Marcus Brger
88
Marcus Brger
89
; should know if there is a value: ; may have a current value: ; may have a key:
(may return NULL at any time)
Iterators
; ; ; ; only know one element at a time only require memory for the current element forward access only Access done by method calls
Containers
; require memory for all elements ; allow to access any element directly ; can create external Iterators or are internal Iterators
Marcus Brger Introduction to Object-oriented programming with PHP 92
; ;
; ;
Marcus Brger
93
PHP Iterators
; ; ; ; ; Anything that can be iterated implements Traversable Objects implementing Traversable can be used in foreach User classes cannot implement Traversable IteratorAggregate is for objects that use external iterators Iterator is for internal traversal or external iterators
Traversable
Iterator IteratorAggregate
+ getIterator () : Iterator
+ + + + +
: : : : :
Marcus Brger
94
Implementing Iterators
Traversable
Iterator IteratorAggregate + + + + + rewind () valid () current () key () next () : : : : : void boolean mixed mixed void
+ getIterator () : Iterator
IteratorImpl AggregateImpl + + + + + <<Implement>> <<Implement>> <<Implement>> <<Implement>> <<Implement>> rewind () valid () current () key () next () : : : : : void boolean mixed mixed void
Marcus Brger
95
<?php $o = new ArrayIterator(array(1, 2, 3)); foreach($o as $key => $val) { // some code } ?> Marcus Brger Introduction to Object-oriented programming with PHP 96
Marcus Brger
98
<?php $it = get_resource(); foreach(new Filter($it, $filter_param) as $key=>$val) { // access filtered data only } ?>
Marcus Brger Introduction to Object-oriented programming with PHP 99
Debug Session
<?php PHP 5.1 class ArrayIterator { protected $ar; function __construct(Array $ar) { $this->ar = $ar; } function rewind() { rewind($this->ar); } fucntion valid() { return !is_null(key($this->ar)); } function key() { return key($this->ar); } fucntion current() { return current($this->ar); } function next() { next($this->ar); } } ?> <?php $a = array(1, 2, 3); $o = new ArrayIterator($a); foreach($o as $key => $val) { echo "$key => $va\n"; } ?>
Marcus Brger
100
; ; ;
Why not just use arrays: foreach($some_array as $item) {/*...*/} Aren't we making life more difficult than need be? No! For simple aggregations the above works fine (though its slow), but not everything is an array. What about:
; Buffered result sets ; Lazy Initialization ; Directories ; Anything not already an array
Marcus Brger
101
Iterators by example
; Using Iterators you can efficiently grab all groups from INI files The building blocks:
; ; ; ; ; A class that handles INI files An abstract filter Iterator A filter that filters group names from the INI file input An Iterator to read all entries in the INI file Another filter that allow to search for specific groups
Marcus Brger
102
function __construct($file, $handler) { if (!$this->db = dba_open($file, 'r', $handler)) throw new Exception("Could not open file $file"); } function __destruct() { dba_close($this->db); } private function fetch_data($key) { if (($this->key = $key) !== false) $this->val = dba_fetch($this->key, $this->db); } function rewind() { $this->fetch_data(dba_firstkey($this->db)); } function next() { $this->fetch_data(dba_nextkey($this->db)); } function current() { return $this->val; } function valid() { return $this->key !== false; } function key() { return $this->key; }
Introduction to Object-oriented programming with PHP 103
Marcus Brger
} ?>
Marcus Brger
104
Putting it to work
<?php
Avoid calling __autoload()
if (!class_exists('KeyFilter', false)) { require_once('keyfilter.inc'); } if (!class_exists('IniGroups', false)) { require_once('inigroups.inc'); } $it = new IniGroups($argv[1]); if ($argc>2) { $it = new KeyFilter($it, $argv[2]); } foreach($it as $group) { echo $group . "\n"; } ?>
Marcus Brger Introduction to Object-oriented programming with PHP 106
Conclusion so far
; ; Iterators require a new way of programming Iterators allow to implement algorithms abstracted from data Iterators promote code reuse Some things are already in SPL
; Filtering ; Handling recursion ; Limiting
; ;
Marcus Brger
107
Design Patterns
Marcus Brger
108
Marcus Brger
109
Not so much.
Patterns sources outside OOP include: ; ; ; Architecture (the originator of the paradigm) User Interface Design (wizards, cookie crumbs, tabs) Cooking (braising, pickling)
Marcus Brger
110
Marcus Brger
111
Aggregator Pattern
; Problem: You have collections of items that you operate on frequently with lots of repeated code. Remember our calendars:
foreach($entries as $entry) { echo $entry; }
Solution: Create a container that implements the same interface, and perfoms the iteration for you.
Marcus Brger
112
Aggregator Pattern
class EntryAggregate extends Entry { protected $entries; ... public function display() { foreach($this->entries as $entry) { $entry->display(); } public function add(Entry $e) { array_push($this->entries, $e); } } By extending Entry, the aggregate can actually stand in any place that entry did, and can itself contain other aggregated collections.
Marcus Brger Introduction to Object-oriented programming with PHP 113
Proxy Pattern
; Problem: You need to provide access to an object, but it has an interface you dont know at compile time. Solution: Use accessor/method overloading to dynamically dispatch methods to the object. Discussion: This is very typical of RPC-type facilities like SOAP where you can interface with the service by reading in a definitions file of some sort at runtime.
Marcus Brger
114
Marcus Brger
115
Observer Pattern
; Problem: You want an object to automatically notify dependents when it is updated. Solution: Allow 'observer' to register themselves with the observable object. Discussion: An object may not apriori know who might be interested in it. The Observer pattern allows objects to register their interest and supply a notification method.
Marcus Brger
116
Object Storage
class ObjectStorage { protected $storage = array(); function attach($obj) { foreach($this->storage as $o) { if ($o === $obj) return; } $this->storage[] = $obj; } function detatch($obj) { foreach($this->storage as $k => $o) { if ($o === $obj) { unset($this->storage[$k]); return; } } }
Marcus Brger
118
Marcus Brger
119
class MySubject implements Subject { protected $observers; public function __construct() { $this->observer = new ObjectStorage; } public function attach(Observer $o) { $this->observers->attach($o); } public function detach(Observer $o) { $this->observers->detach($o); } public function notify() { foreach($this->observers as $o) $o->update($this); } } class MyObserver implements Observer { public function update(Subject $s) { // do logging or some other action } }
php r 'print_r(array_keys(spl_classes()));'
; ;
Extension information/configuration
php --ri <Extension>
Marcus Brger
121
Reference
; ; ; Everythining about PHP http://php.net These slides http://talks.somabo.de SPL Documentaion & Examples http://php.net/~helly/php/ext/spl http://cvs.php.net/php-src/ext/spl/examples http://cvs.php.net/php-src/ext/spl/internal George Schlossnagle Advanced PHP Programming Andi Gutmans, Stig Bakken, Derick Rethans PHP 5 Power Programming
; ;
Marcus Brger
122