CSC/ECE 517 Fall 2012/ch1 1w34 vd: Difference between revisions
Line 211: | Line 211: | ||
say 'A'; | say 'A'; | ||
} | } | ||
<br/> package B; | |||
use parent 'A'; | use parent 'A'; | ||
sub speak { | sub speak { | ||
Line 219: | Line 218: | ||
say 'B'; | say 'B'; | ||
} | } | ||
<br/> package C; | |||
use parent 'B'; | use parent 'B'; | ||
sub speak { | sub speak { | ||
Line 227: | Line 225: | ||
say 'C'; | say 'C'; | ||
} | } | ||
<br/> my $c = C->new(); | |||
$c->speak(); | $c->speak(); | ||
Revision as of 23:13, 14 September 2012
Introduction
Re- implantation of methods in PHP 5
The object model in PHP5 was rewritten to include OO features such as final, abstract and visibility for classes and methods and improve the overall performance of the language. Re-implantation of methods in Php 5 can be achieved in the following manner:
Object Inheritance
This is an important OO feature that PHP uses in its object model. When a subclass extends from a parent class, it inherits all the public and protected methods from the parent class. The issues that affect how the inherited methods behave are:
Method Visibility
All methods that are defined as ‘public’ and ‘protected’ in the parent class are ‘visible’ in the subclass. Public and protected are access modifiers that define the visibility of methods between different classes. Methods defined as ‘private’ access are not visible in the subclass. Methods declared without any access keyword are ‘public’.
Example:
<?php class GameClass { public function_construct(){ } //Declare a public constructor
public function GamePublic(){ } //Declare a public method
protected function GameProtected(){ } //Declare a protected method
private function GamePrivate(){ } //Declare a private method
function Play() //This is public
{ $this->GamePublic(); $this->GameProtected(); $this->GamePrivate(); } } ?> $mygame = new GameClass;
$mygame->GamePublic(); // Works
$mygame->GameProtected(); // Fatal Error
$mygame->GamePrivate(); // Fatal Error
$mygame->Play(); // Public, Protected and Private work
class BoardGame extends GameClass {
//This is public
function PlayDice()
{
$this->GamePublic();
$this->GameProtected();
$this->GamePrivate(); // Fatal Error
}
}
$myboard = new BoardGame;
$myboard->GamePublic(); // Works
$myboard->PlayDice(); // Public and Protected work, not Private
Overriding
If a subclass defines a new method with the same name and signature as that of the method from the parent class then an object of the subclass calling that method will execute the implementation of the method defined in the subclass. Example: change this example for overriding
<?php class game { public function game-name($string) { echo 'Game: ' . $string . PHP_EOL; } public function play() { echo 'I like this game.' . PHP_EOL; } }
class chess-game extends game { public function game-name($string) { echo 'Board Game: ' . $string . PHP_EOL; } }
$gm = new game (); $cg = new chess-game(); $game->game-name('cricket'); // Output: 'Game: cricket' $gm->play(); // Output: 'I like this game' $cg->game-name('chess'); // Output: 'Board Game: chess' $cg->play(); // Output: 'I like this game' ?>
Scope Resolution
When a subclass extends a class, then the overridden and overloaded methods of the parent class can be called, using the scope resolution operator (::) inside the subclass.
<?php class ParentClass { protected function parentFunc() { echo "ParentClass::parentFunc()\n"; } }
class ChildClass extends ParentClass { // Override parent's definition public function parentFunc() { // Call the parent function parent::parentFunc(); echo "ChildClass::parentFunc()\n"; } }
$class = new ChildClass(); $class->parentFunc(); ?> Output ParentClass::parentFunc() ChildClass::parentFunc()
Class Abstraction
Abstract methods in PHP 5 are methods inside abstract class that only provide signature for the method without any actual implementation to it. An abstract method has an abstract keyword at the beginning of the method declaration. A class containing even a single abstract method should be declared as abstract by adding the abstract keyword to its declaration. Any class inheriting from an abstract class should provide implementation to all of the abstract methods or declare it abstract. No class can inherit from more than one abstract class. The inheriting class, should have the same signature for the inherited abstract methods and the same or less restrictive visibility as defined for the methods in the abstract class.
<?php abstract class ParentAbstractClass { // Method without definition abstract protected function getName(); abstract protected function setName($name); // Method with definition public function printName() { print $this->getName() . "\n"; } } class ConcreteChild extends ParentAbstractClass { //Method from abstract class implemeted protected function getName() { return "ConcreteChild"; } //Method from abstract class implemeted public function setName($name) { return "ConcreteChild : {$name}"; } } class ConcreteChild2 extends ParentAbstractClass { //Method from abstract class implemeted public function getname() { return "ConcreteChild2"; } //Method from abstract class implemeted public function setName($name) { return "ConcreteChild2 : {$name}"; } }
$class1 = new ConcreteChild; $class1->printName(); echo $class1->setName('FOO') ."\n"; $class2 = new ConcreteChild2; $class2->printName(); echo $class2->setName('FOO') ."\n"; ?> The above example will output: ConcreteChild ConcreteChild : FOO ConcreteChild2 ConcreteChild2 : FOO
Object Interfaces
Interface in php is a mechanism that specifies methods that a class requires to implement, without having to provide any implementation to these methods inside the interface. An interface is declared like any other class, just that it is prefixed by the interface keyword and none of its methods have any content to them. A class providing implementation to the methods of an interface has the implements keyword followed by the class name for that class. Similarly, an interface can be inherited by another interface so that, a class implementing the interface that is lowest in the inheritance hierarchy gets to implement the methods from all the interfaces. Methods inside the interface being implemented by a class should have the same signature as that of the interface. Note: An interface cannot be instantiated.
<?php interface food { //Interface method with no implementation public function eat(); }
interface fruit { //Interface method with no implementation public function fruitName(); }
interface Apple extends food, fruit { //Interface method with no implementation public function juice(); }
class GreenApple implements Apple { //Implementing methods from all the interfaces public function eat() { echo “Food: eat()”; } public function fruitName() { echo “Fruit: fruitName()”; } public function juice() { echo “Apple: juice()”; } } ?>
The class GreenApple will implement all the methods that it has inherited from all the interfaces in inheritance hierarchy.
Re- implantation of methods in Perl
Unlike many other OO languages, Perl does not have any special syntax for defining class. Instead, a class can be simply described as a package that acts as a namespace for variables and methods contained inside that package. Since a package does not behave like a conventional class the methods inside the class may or may not expect an object or class reference as the first argument. Each class (or package as we said) contains a @ISA array. This array is required to store the package name (of type string) of all those classes that have been inherited by that class. Inheritance of methods in Perl is a built-in feature but in order to inherit attributes, explicit code needs to be written inside the class inheriting attributes from another class. So, when a class has been inherited by a subclass, all the methods from the parent’s package are implicitly available to the subclass.
package Fruit::Apple; use parent 'Fruit'; # sets @Fruit::Apple::ISA = ('Fruit'); my $apple = Fruit::Apple->new( 'GreenApple', $data ); $apple->save();
The Fruit::Apple class doesn’t have a save() method defined in it. So Perl tries to find the save() method in the parent class for Fruit::Apple, that is the Fruit class. If the Fruit class also didn’t have the save() method, Perl dies. In this case, although the method save() of the Fruit class is being called, the object saved will be that of the fruit::Apple object.
Method Overriding
Within the subclass, we can override the methods of the parent class. When calling the method from an object reference of the subclass, the implementation inside the subclass will be executed. We can also execute the implementation of any parent class method inside the subclass using the Super keyword. With this keyword, any method from the parent class can be called inside the subclass but this does not hold for subroutine calls and class methods. SUPER is a pseudo class, so methods of the parent class cannot be called as the methods of the SUPER class.
SUPER::save($data); # FAIL: looks for save() sub in package SUPER SUPER->save($data); # FAIL: looks for save() method in class # SUPER $thing->SUPER::save(); # Okay: looks for save() method in parent# classes
Super Keyword
In a multi-level hierarchy, the super keyword is resolved not on the basis of the object’s class but on the basis of the package inside which it is being called. This allows classes in a multi-level hierarchy to call its immediate parent’s method using the super keyword. Example
package A; sub new { return bless {}, shift; } sub speak { my $self = shift; $self->SUPER::speak(); say 'A'; }
package B;
use parent 'A'; sub speak { my $self = shift; $self->SUPER::speak(); say 'B'; }
package C;
use parent 'B'; sub speak { my $self = shift; $self->SUPER::speak(); say 'C'; }
my $c = C->new();
$c->speak();
Output:
A //Method speak() from package A will complete execution first
B // Followed by the speak() method from package B
C //And lastly the method speak() from package C will finish execution
Multiple Inheritance
Though multiple inheritance is bound to raise design issues, nevertheless it provides a convenient mechanism for code reuse and implementation. Perl supports multiple inheritance with a complicated method lookup mechanism. When a class is inheriting multiple classes, then the names for all the classes will go inside the @ISA array. When resolving method names, Perl will search for the method in the following order and stops as soon as it finds an implementation: 1.Inside the class on which the method call has been made. 2.The first class in the @ISA array and if not found it will go up to the inheritance hierarchy for this class until it finds the method. 3.The second class in the @ISA array and if not found it will go up to the inheritance hierarchy for this class until it finds the method. 4.The third class in the @ISA array and so on… So Perl will lookup into the inheritance hierarchy of each of the classes in the @ISA array in a depth-first search from left to right manner. In doing so, it may happen, that a grand-parent class is visited before its child class as can be understood from the following diagram. Grandparent 1 Grandparent 2 / \ / Parent 1 Parent 2 \ / Child When calling a method on the Child class, it will be resolved in the oreder – Child, Parent 1, Granparent 1, Parent 2, Grandparent 2. This might be a problem as we are checking Grandparent 1 before checking all of its subclasses down the hierarchy. This problem can be solved by using the C3 resolution from the mro pragma. The c3 resolution order ensures that all the classes of a parent class are searched before the parent class itself. So the order of resolution will be – Child, Parent 1, Parent 2, Grandparent 1, Grandparent 2. The resolution is no more depth-first search now.
package Child; use mro 'c3'; use parent 'Parent1', 'Parent2';