Thursday 28 March 2019

Abstract Class & Method

Abstract Class

  • An abstract class must be declared with an abstract keyword.
  • It can have abstract and non-abstract methods.
  • It cannot be instantiated.
  • It can have constructors and static methods also.
  • It can have final methods which will force the subclass not to change the body of the method.
Abstract classes contain one or more abstract methods. 
An abstract method is a method that is declared, but contains no implementation. 
Abstract classes may not be instantiated, and require sub-classes to provide implementations for the abstract methods.

1. Can not instantiate abstract class: Classes defined as abstract may not be instantiated, and any class that contains at least one abstract method must also be abstract.

Example below :
abstract class AbstractClass
{
  abstract protected function getValue();
  abstract protected function prefixValue($prefix);
  public function printOut() {
    echo "Hello how are you?";
  }
}

$obj = new AbstractClass();
$obj->printOut();
//Fatal error: Cannot instantiate abstract class AbstractClass

2. Any class that contains at least one abstract method must also be abstract: Abstract class can have abstract and non-abstract methods, but it must contain at least one abstract method. If a class has at least one abstract method, then the class must be declared abstract.

Note: Traits support the use of abstract methods in order to impose requirements upon the exhibiting class.

Example below :
class Non_Abstract_Class
{
   abstract protected function getValue();
   public function printOut() {
     echo "Hello how are you?";
   }
}

$obj=new Non_Abstract_Class();
$obj->printOut();
//Fatal error: Class Non_Abstract_Class contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Non_Abstract_Class::getValue)

3. An abstract method can not contain body: Methods defined as abstract simply declare the method's signature - they cannot define the implementation. But a non-abstract method can define the implementation.

abstract class AbstractClass
{
   abstract protected function getValue(){
     return "Hello how are you?";
   }
   public function printOut() {
     echo $this->getValue() . "\n";
   }
}

class ConcreteClass1 extends AbstractClass
{
  protected function getValue() {
    return "ConcreteClass1";
  }
  public function prefixValue($prefix) {
    return "{$prefix}ConcreteClass1";
  }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";
//Fatal error: Abstract function AbstractClass::getValue() cannot contain body

4. When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child :If you inherit an abstract class you have to provide implementations to all the abstract methods in it.

abstract class AbstractClass
{
  // Force Extending class to define this method
  abstract protected function getValue();
  // Common method
  public function printOut() {
    print $this->getValue() . "<br/>";
  }
}

class ConcreteClass1 extends AbstractClass
{
  public function printOut() {
    echo "dhairya";
  }
}
$class1 = new ConcreteClass1;
$class1->printOut();
//Fatal error: Class ConcreteClass1 contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (AbstractClass::getValue)

5. Same (or a less restricted) visibility:When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child; additionally, these methods must be defined with the same (or a less restricted) visibility. 

For example, if the abstract method is defined as protected, the function implementation must be defined as either protected or public, but not private.

Note that abstract method should not be private.

abstract class AbstractClass
{
  abstract public function getValue();
  abstract protected function prefixValue($prefix);
  public function printOut() {
    print $this->getValue();
  }
}

class ConcreteClass1 extends AbstractClass
{
  protected function getValue() {
    return "ConcreteClass1";
  }
  public function prefixValue($prefix) {
    return "{$prefix}ConcreteClass1";
  }
}
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."<br/>";
//Fatal error: Access level to ConcreteClass1::getValue() must be public (as in class AbstractClass)

6. Signatures of the abstract methods must match: When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child;the signatures of the methods must match, i.e. the type hints and the number of required arguments must be the same. 

For example, if the child class defines an optional argument, where the abstract method's signature does not, there is no conflict in the signature.

abstract class AbstractClass
{
    abstract protected function prefixName($name);
}

class ConcreteClass extends AbstractClass
{
    public function prefixName($name, $separator = ".") {
        if ($name == "Pacman") {
            $prefix = "Mr";
        } elseif ($name == "Pacwoman") {
            $prefix = "Mrs";
        } else {
            $prefix = "";
        }
        return "{$prefix}{$separator} {$name}";
    }
}

$class = new ConcreteClass;
echo $class->prefixName("Pacman"), "<br/>";
echo $class->prefixName("Pacwoman"), "<br/>";
//output: Mr. Pacman
//        Mrs. Pacwoman

7. Abstract class doesn't support multiple inheritance: Abstract class can extends another abstract class,Abstract class can provide the implementation of interface.But it doesn't support multiple inheritance.

interface MyInterface{
    public function foo();
    public function bar();
}

abstract class MyAbstract1{
    abstract public function baz();
}


abstract class MyAbstract2 extends MyAbstract1 implements MyInterface{
    public function foo(){ echo "foo"; }
    public function bar(){ echo "bar"; }
    public function baz(){ echo "baz"; }
}

class MyClass extends MyAbstract2{
}

$obj=new MyClass;
$obj->foo();
$obj->bar();
$obj->baz();
//output: foobarbaz

Note: Please note order or positioning of the classes in your code can affect the interpreter and can cause a Fatal error. So, when using multiple levels of abstraction, be careful of the positioning of the classes within the source code.

below example will cause Fatal error: Class 'horse' not found

class cart extends horse {
    public function get_breed() { return "Wood"; }
}

abstract class horse extends animal {
    public function get_breed() { return "Jersey"; }
}

abstract class animal {
    public abstract function get_breed();
}

$cart = new cart();
print($cart->get_breed());

Reference: https://stackoverflow.com/questions/2558559/what-is-abstract-class-in-php

Points on abstract class.
1. Declare classes and methods as abstract?
To declare a class as abstract, prefix the name of the class with the abstract keyword.

Example: abstract class Car { }

Declare abstract method with "abstract" keyword within the abstract class. Abstract method don't have body, only name and parameters inside parentheses.

Example: Create a public abstract method "calcNumMilesOnFullTank()". This method is skeleton for methods we will create in the child classes. These methods will return the number of miles a car can be driven on a tank of gas.

// Abstract classes are declared with the abstract keyword, and contain abstract methods.
abstract class Car {
  abstract public function calcNumMilesOnFullTank();
}

If an abstract method is created in the class, the class must be abstract.

2. Can an abstract class have non abstract methods?
An abstract class can have non abstract methods. In fact, it can even have properties, and properties couldn't be abstract.

Example: Add a protected property $tankVolume and public method setTankVolume().

abstract class Car {
  // Abstract classes can have properties
  protected $tankVolume;
  // Abstract classes can have non abstract methods
  public function setTankVolume($volume) {
    $this -> tankVolume = $volume;
  }
  // Abstract method
  abstract public function calcNumMilesOnFullTank();
}

3. Create child classes from an abstract class?
Objects cannot created from abstract classes. Create child classes that inherit the abstract class code. Child class will inherit the abstract class with the help of "extends" keyword.

The child classes that inherit from abstract classes must add bodies to the abstract methods.
Example: Create a child class "Honda", define abstract method in it which is inherited from the parent, calcNumMilesOnFullTank().

class Honda extends Car {
  // Since we inherited abstract method, we need to define it in the child class, 
  // by adding code to the method's body.
  public function calcNumMilesOnFullTank()
  {
    $miles = $this -> tankVolume*30;
    return $miles;
  }
}

We can create another child class from the Car abstract class and call it Toyota, and here again define the abstract method calcNumMilesOnFullTank() with a slight change in the calculation. We will also add to the child class its own method with the name of getColor() that returns the string "beige".

class Toyota extends Car {
  // Since we inherited abstract method, we need to define it in the child class, 
  // by adding code to the method's body.
  public function calcNumMilesOnFullTank() {
    return $miles = $this -> tankVolume*33;
  }

  public function getColor() {
    return "beige";
  }
}

Example: create a new object, $toyota1, with volume of 10 Gallons, and let it return the number of miles on full tank and the car's color.

$toyota1 = new Toyota();
$toyota1 -> setTankVolume(10);
echo $toyota1 -> calcNumMilesOnFullTank();//330
echo $toyota1 -> getColor();//beige

No comments:

Post a Comment