Class Abstraction

PHP 5 introduces abstract classes and methods. It is not allowed to create an instance of a class that has been defined as abstract. Any class that contains at least one abstract method must also be abstract. Methods defined as abstract simply declare the method's signature they cannot define the implementation.

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 weaker) visibillity. For example, if the abstract method is defined as protected, the function implementation must be defined as either protected or public.

例子 19-16. Abstract class example

<?php
abstract
class AbstractClass
{
    
// Force Extending class to define this method
    
abstract protected function getValue();
    
abstract protected function prefixValue($prefix);

    
// Common method
    
public function printOut() {
        print
$this->getValue() . "\n";
    }
}

class
ConcreteClass1 extends AbstractClass
{
    
protected function getValue() {
        return
"ConcreteClass1";
    }

    
public function prefixValue($prefix) {
        return
"{$prefix}ConcreteClass1";
    }
}

class
ConcreteClass2 extends AbstractClass
{
    
public function getValue() {
        return
"ConcreteClass2";
    }

    
public function prefixValue($prefix) {
        return
"{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo
$class1->prefixValue('FOO_') ."\n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo
$class2->prefixValue('FOO_') ."\n";
?>

上例将输出:

ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

Old code that has no user-defined classes or functions named 'abstract' should run without modifications.


add a note add a note User Contributed Notes
david at mr-t dot nl
25-Jul-2006 11:27
It took me a while to figure this out and i couldn't find it easily in the documentation anywhere.

If you want to override a method from a base class and want to call the base class in the method, then you have to use the parent::function() syntax, even though the method isn't static. There is no $base variable in php that i know of.

Expamle:
<?php
public abstract
class BasePerson() {
 
/*
   * alot of code..
   */
 
public function getName() {
   return
$this->name;
  }
}

public class Person() extends BasePerson {
 
/*
   * alot of code..
   */
  // override of base getName()..
 
public function getName() {
  
// you would expect $base->getName() instead of parrent::getName()...
  
return htmlspecialchars(parent::getName());
  }
}
?>

Hope this helps!
James
17-May-2006 01:10
A nice tutorial on PHP5's abstract classes and interfaces:

Working with php5 class types abstract classes and interfaces.

http://www.phpfive.net/article4.htm
gsteren at gmail dot com
06-Mar-2006 09:48
Abstract classes allow the declaration of protected abstract methods, which cannot be emulated with the use of an interface and a concrete superclass.

Even private abstract methods can be declared, although I fail to see the use in them, as subclasses will not see them anyway.
rasto_klc (at) yahoo (dot) obvious
29-Dec-2005 05:27
Variable-length argument lists in abstract methods will generate fatal error if derived. Here is an simple example:

<?php
// common wrap for all validators is forcing uniform interface
abstract class ValidatorWrap {

  
// just example why variable-length arguments are needed
  
public function __construct()
   {
       if (
func_num_args() > 0) {
          
$arg_list = func_get_args();
          
call_user_func_array(array(&$this, 'setupValidator'), $arg_list);
       } else {
          
$this->setupValidator();
       }
      
// continue with construction
  
}

  
// amount of arguments is specific to validator implementation
  
abstract public function setupValidator();

  
// known interface
  
abstract public function validate($value);
}

class
Validator1 extends ValidatorWrap {

  
protected $pattern = '';

  
// this will generate PHP Fatal error because $pattern is not expected
  
public function setupValidator($pattern)
   {
      
$this->pattern = $pattern;
   }

  
// this will do OK
  
public function validate($value)
   {
       return
preg_match($this->pattern, $value);
   }
}

// make numeric validator
$validator = new Validator1('/^\d+$/');
echo (int)
$validator->validate($_REQUEST['digits']);
?>

I need it to work so I just redefine troublemaking function as follows:

<?php
   public
function setupValidator() { }
?>

This will give me functionality I need and generates only PHP Strict Standards warning.
turgut85 at hotmail dot com
03-Dec-2005 01:38
<?php

// Design Pattern ABSTRACT FACTORY  implementation //

abstract class AbstractFactory {
  
public abstract function CreateProductA();  // return data type is AbstractProductA
  
public abstract function CreateProductB();  // return data type is AbstractProductB
}

// Abstract factory #1 //
class ConcreteFactory1 extends AbstractFactory {

  
public function CreateProductA() { // return data type is AbstractProductA
      
return new ProductA1();
   }

  
public function CreateProductB() { // return data type is AbstractProductB
      
return new ProductB1();
   }
}

// Abstract factory #2 //
class ConcreteFactory2 extends AbstractFactory {

  
public function CreateProductA() { // return data type is AbstractProductA //
      
return new ProductA2();
   }

  
public function CreateProductB() { // return data type is AbstractProductB //
      
return new ProductB2();
   }
}

// "AbstractProductA" //
abstract class AbstractProductA {
}

// "AbstractProductB" //
abstract class AbstractProductB {
  
public abstract function Interact($a); // return type is void // // input type is  AbstractProductA
}

// "ProductA1" //
class ProductA1 extends  AbstractProductA {
}

// "ProductB1" //
class ProductB1 extends  AbstractProductB {

  
public function Interact($a) {
       echo
__CLASS__." interacts with ".__METHOD__."\n";
      
var_dump($a);
   }
}

// "ProductA2"
class ProductA2 extends AbstractProductA {
}

// "ProductB2"
class ProductB2 extends AbstractProductB {
  
public function Interact($a) {
       echo
__CLASS__." interacts with ".__METHOD__."\n";
      
var_dump($a);
   }
}

class
Client {

  
private  $AbstractProductA;                            // type AbstractProductA;
  
private  $AbstractProductB;                            // type AbstractProductB;

   // Constructor
  
public function __construct($factory) {
      
$this->AbstractProductB = $factory->CreateProductB();
      
$this->AbstractProductA = $factory->CreateProductA();
   }

  
public function Run() {
      
$this->AbstractProductB->Interact($this->AbstractProductA);
   }
}

// Abstract factory #1
$factory1 = new ConcreteFactory1();
$c1 = new Client($factory1);
$c1->Run();

// Abstract factory #2
$factory2 = new ConcreteFactory2();
$c2 = new Client($factory2);
$c2->Run();

// TURGUT Z. YESILYURT, MS
// Software Developer
// NewJersey, USA

?>
Output::

ProductB1 interacts with ProductB1::Interact
object(ProductA1)#4 (0) {
}
ProductB2 interacts with ProductB2::Interact
object(ProductA2)#8 (0) {
}
mail dot phatlip at gmail dot com
07-Nov-2005 01:04
just RE: ramonzamora at gmail dot com

Abstraction is 'stricter' than inheritance+implementation as it contains 'rules' about the visibility of the methods that are inherited, as well as the fact that it saves needing two classes to get a job done.

The fact you cannot instantiate an abstract class can be benificial also.
ramonzamora at gmail dot com
28-Aug-2005 06:46
so abstract clases are the same than inheritance+interfaces??

<?php

//using inheritance+interfaces

interface callA{
  
protected function callA();
}

class
callB{
  
protected $b;
  
protected function callB(){
       return
$this->b;
   }
}

class
caller extends callB implements callA{
  
protected $a;
  
public function __construct($a,$b){
      
$this->a=$a;
      
$this->b=$b;
   }
  
protected function callA(){
       return
$this->a;
   }
 
  
public function callAB(){
       return
$this->callA().$this->callB();
   }
}

$caller=new caller('a','b');
$caller->callAB();

//using abstract class

abstract class callAB{
  
abstract protected function callA();
  
protected $b;
  
protected function callB(){
       return
$this->b;
   }
}

class
caller extends callAB{
  
protected $a;
  
public function __construct($a,$b){
      
$this->a=$a;
      
$this->b=$b;
   }
  
protected function callA(){
       return
$this->a;
   }
  
public function callAB(){
       return
$this->callA().$this->callB();
   }
}

$caller=new caller('a','b');
$caller->callAB();
?>

the only difference i see is that using inheritance+interfaces you can instantiate the parent but using abstract classes you can't