260 likes | 406 Views
UFCEUS-20-2 : Web Programming. Lecture 6 : Object Oriented PHP (2). Refactoring the Person/Student classes (1) : the Person Class. (from last week) Person class:. class Person { public $name; public $dob; public $gender; function __construct($n, $d, $g){ $this->name = $n;
E N D
UFCEUS-20-2 : Web Programming Lecture 6 : Object Oriented PHP (2)
Refactoring thePerson/Studentclasses (1) : the Person Class (from last week) Person class: class Person { public $name; public $dob; public $gender; function __construct($n, $d, $g){ $this->name = $n; $this->dob = $d; $this->gender = $g; } function get_name(){ return $this->name; } } public by default
(2) : the Student subclass inheritance or sub-classing (from last week) Student class: class Student extends Person { public $programme; public $number; function __construct($n, $d, $g, $p, $no) { parent::__construct($n, $d, $g); $this->programme = $p; $this->number = $no; } } call parent method
(3) : instantiate a Student object and call the get_name() method // instantiate a student object $s $s = new Student ('Reuben', '1993/10/25', 'male', 'Systems Analysis', '12345678'); // invoke the get_name() method echo $s->get_name(); //filters up to parent Output: Reuben Note on UML 2 notation: + public # protected – private
(4) : add new get_age() method refactoredPersonclass: date_default_timezone_set('Europe/London'); class Person { private $name, $dob, $gender; function __construct($n, $d, $g) { $this->name = $n; $this->dob = $d; $this->gender = $g; } public function __get($var) { return $this->$var; } public function get_age() { return floor((time() - strtotime($this->dob))/31556926); } } calculates current age
(5) : using the “magic” __get() method include_once('Person_Class.php'); class Student extends Person { private $programme; private $number; public function __construct($n, $d, $g, $p, $no) { parent::__construct($n, $d, $g); $this->programme = $p; $this->number = $no; } public function __get($var) { if (preg_match('/name|dob|gender/', $var)) { return parent::__get($var); } return $this->$var; } } overrides parents __get
!! Code smell alert : principle of loose coupling broken public function __get($var) { if (preg_match('/name|dob|gender/', $var)) { return parent::__get($var); } return $this->$var; } Why?
Correcting a dud example – the refactored Studentclass include_once('Person_Class.php'); class Student extends Person { private $programme; private $number; public function __construct($n, $d, $g, $p, $no) { parent::__construct($n, $d, $g); $this->programme = $p; $this->number = $no; } public function __get($var) { if (preg_match('/programme|number/', $var)) { return $this->$var; } else { return parent::__get($var); } } } corrected
(6) : the Lecturer class Lecturerclass: include_once('Person_Class.php'); class Lecturer extends Person { private $modules=array(); private $room; function __construct($n, $d, $g, $m, $r) { parent::__construct($n, $d, $g); $this->modules = $m; $this->room = $r; } public function __get($var) { if (preg_match('/moduules|room/', $var)) { return $this->$var; } else { return parent::__get($var); } } }
(7) : Testing the Student & Lecturer classes <?php include('Student_Class.php'); include('Lecturer_Class.php'); // instantiate a student object $s $s = new Student ('Reuben', '1993/07/25','male','Systems Analysis', '12345678'); //invoke the __get() method echo $s->name; echo ' is doing '.$s->programme; echo ' and is '.$s->get_age().' years old<br/>'; // instantiate a new Lecturer $l = new Lecturer('Prakash', '1960/09/01','man', array('Web Programming','ISD','PEPI'), '3P16'); // echo name and each array element followed by an & (unless last element) echo $l->name.' teaches '; foreach($l->modules as $module) { echo $module; if (!(end($l->modules)==$module)) {echo ' & ';} } ?> run script
Controlling access with private,protectedand public • php uses access modifiers to control the visibility of attributes and methods (functions) - these modifiers are placed in front of attributes and methods • the default option is public - that is, if no modifier is stated - it is assumed to be public - these can be accessed from inside or outside the class • the private access modifier can only be accessed from inside the class - if, for instance a method is a utility function and only to be used inside the class - private attributes & methods cannot be inherited • the protected access modifier means that the marked item can be accessed from inside the class but also exists in any inherited classes - protected is kind of half way between public and private
class methods are not run on specific a object instance – they have class only scope • from outside they have to be called using the class name • the keyword for class methods and variables is static • inside the class the qualifier self:: is used; • outside the class the qualifier Classname:: is used • example static variable & method: • class StaticExample { • static public $aNum = 0; • static public function sayHello() { • echo 'hello'; • } • // from inside the class • echo self::$aNum; • self::sayHello(); • } • // from outside • echo StaticExample::$aNum; • StaticExample::sayHello(); class methods, variables & constants
class method & variable example (2): static variable class StaticExample { static public $aNum = 0; static public function sayHello() { self::$aNum++; echo 'hello ('.self::$aNum.')<br/>'; } } test_static.php include ('StaticExample.php'); StaticExample::sayHello(); StaticExample::sayHello(); StaticExample::sayHello(); Output? run script no need to instantiate the class
class constants : • cannot be changed (hence ‘constant’) • they are always public • some restrictions on what they can hold (no objects for instance) • declared using the const keyword • not allowed to be defined inside methods class method & constant example : class HowLong { // speed of light (meters per second) const C = 299792458; // average distance from the earth to the sun (meters) const D = 140000000000; // method to calculate how long light takes to // get from the sun to the earth in minutes function minToEarth() { echo (self::D/self::C)/60; } } HowLong::minToEarth(); run script
“final” classes and methods • inheritance is powerful and flexible allowing for sub-classing (specialisation) or overriding methods so that call to a client method will achive radically different results (see our Shape class example from last week) • sometimes though, we require a class or method to remain unchanging – to stop inheritance or overriding • The keyword final puts a stop to inheritance and does not allow methods to be overridden (i.e. you can instantiate a class with a final method but you can’t override that method) • example: • final class Checkout {}; • // try to inherit • class IllegalCheckout extends Checkout { }; • Output: • Fatal error: Class IllegalCheckout may not inherit from final class (Checkout) in C:\xampp\htdocs\php\illegal.php on line 5
Abstract Methods & Classes • OO programs are built around class hierarches • PHP supports single inheritance – so class hierarchies can be visualised as trees • a root class has one or more classes that descend from it, with one or more classes derived from them • abstract methods are methods that behave like placeholders for regular methods in derived classes but unlike regular class methods they do not contain any code • they bind any derived (extended) classes to a contract toimplement the methods defined
Abstract Methods & Classes (continued) • hence – abstract classes define common functionality the base classes must implement • abstract classes are best thought of as a template for derived classes • abstract classescannot be directly instantiated i.e. you cannot create objects from them using the new keyword – they must be extended by concrete classes which can then be instantiated • if a class contains an abstract method – it must be declared as abstract • abstract classes can also contain concrete methods • any method that is declared abstract, when implemented, must contain the same or weaker access level • an abstract class can be extended without implementing all of its methods if the extended class is declared as abstract too – useful for creating hierarchies of objects
Abstract Shape class example (again) // Define abstract class with one abstract method abstract class Shape { public abstract function area(); }
Two concrete classes that extend the Shape class class Circle extends Shape { private $radius; public function __construct($r) { $this->radius = $r; } public function area() { return $this->radius * $this->radius * pi(); } } class Rectangle extends Shape { private $length; private $width; public function __construct($l, $w) { $this->length = $l; $this->width = $w; } public function area() { return $this->length * $this->width; } } must implement contract
Instantiate two objects (Circle, Rectangle) and use their area() method $c = new Circle(22); echo "Area of the circle: " . $c->area() . "<br/>"; $r = new Rectangle(5, 7); echo "Area of the rectangle: " . $r->area() . "<br/>"; run script view code
Abstract Car, FastCar & Street classes example the Car and FastCar classes: abstract class Car { abstract function getMaximumSpeed(); } class FastCar extends Car { function getMaximumSpeed() { return 150; } }
Abstract Car, FastCar& Street classes example (2) the Street class: class Street { protected $speedLimit; protected $cars; public function __construct($speedLimit = 200) { $this->cars = array(); //Initialize the variable $this->speedLimit = $speedLimit; } protected function isStreetLegal($car) { if($car->getMaximumSpeed() < $this->speedLimit) { return true; } else { return false; } } public function addCar($car) { if($this->isStreetLegal($car)) { echo 'The Car was allowed on the road.'; $this->cars[] = $car; } else { echo 'The Car is too fast and was not allowed on the road.'; } } }
Instantiate Street & FastCar objects and add car to cars[] array if legal (i.e. under 200) $street = new Street(); $street->addCar(new FastCar()); view code run script
Emulating multiple inheritance with interfaces • whilst abstract classes can have concrete methods (i.e. provide a measure of implementation) - interfaces are pure templates; • hence an interface can only define functionality but can never implement it; • interfaces offer a way of inheriting from a single parent while sharing an extra set of common features that don’t necessarily apply to all child classes; • any class that that incorporates an interface is committed to a contract to implement all the methods defined in the interface; • all methods declared in an interface are public; • it’s possible for interfaces to have constants but not instance variables. Interface constants work exactly like class constants except they cannot be overridden by a class/interface that inherits it;
Emulating multiple inheritance with interfaces (example) class Vehicle { private $name, $model; function __construct($make, $model) { $this->make = $make; $this->model = $model; } function __get($value) { return $this->$value; } } interface TestDrive_Interface { function drive($to, $from); } class Bike extends Vehicle {} class Car extends Vehicle implements TestDrive_Interface { function drive($to='there', $from='here') { $this->to = $to; $this->from = $from; return "from $this->from to $this->to"; } } $bike = new Bike('Raleigh', 'Chopper'); echo $bike->make.' '.$bike->model.'<br/>'; $car = new Car('Lotus', 'Esprit'); echo $car->drive('Swindon', 'Bristol'); run script
autoloading classes • in php4 classes had to loaded with the include or require keywords • in php5 classes can be loaded dynamically and on a need to use basis by using a “magic” method (or interceptor function) called __autoload • example: • function __autoload($className) { • include_once($className.'_Class.php'); • } • //we have a class called Person_Class.php hence • $person = new Person('Reuben', '1993/07/25','male'); • // will work; hence • echo $person->name; //is fine run script