类与对象
在线手册:中文  英文

抽象类

PHP 5 支持抽象类和抽象方法。定义为抽象的类不能被实例化。任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。

继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。 这也适用于 PHP 5.4 起的构造函数。在 PHP 5.4 之前的构造函数声明可以不一样的。

Example #1 抽象类示例

<?php
abstract class AbstractClass
{
 
// 强制要求子类定义这些方法
    
abstract protected function getValue();
    abstract protected function 
prefixValue($prefix);

    
// 普通方法(非抽象方法)
    
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

Example #2 抽象类示例

<?php
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"), "\n";
echo 
$class->prefixName("Pacwoman"), "\n";
?>

以上例程会输出:

Mr. Pacman
Mrs. Pacwoman

老代码中如果没有自定义类或函数被命名为“abstract”,则应该能不加修改地正常运行。


类与对象
在线手册:中文  英文

用户评论:

passerbyxp at gmail dot com (2013-01-08 10:56:25)

It's not quite clear in this document, so in case someone wonder, abstract method can be static:

<?php
abstract class FOO
{
    abstract static function 
dump();
}
class 
BAR extends FOO
{
    static function 
dump(){var_dump("BAR");}
}
BAR::dump(); // string(3) "BAR"

class FAULT extends FOO
{
    function 
pr(){var_export("WTF");}
// FATAL error
?>

oliver at ananit dot de (2011-11-27 08:07:25)

Abstract classes may have an final constructor, and sometime it makes sense to implement a class with a final constructor.

<?php
abstract class AbstractModel
{
    
//our models must use the default constuctor
        
public final function __construct(){}
    public function 
inject($array){
        foreach(
array_keys(get_class_vars(get_called_class()))  as $property){
            
$this->$property $array[$property];
        }
    }
}

class 
ProductModel extends AbstractModel
{
    public 
$name;
    public 
$price;
    protected 
$id;
    
    public function 
getId(){return $this->id;}
}

class 
Factory{
    private 
$dataSource;
    public function 
__consruct($dataSource){
        
$this->dataSource $dataSource;
    }
    
    public function 
get($class$table$filter$orderby$limit){
        
$result = array();
        foreach(
$datasource->fetchAssoc($table$filter$orderby$limit) as $rawData){
            
$obj = new $class();//this can only work if ALL models have a default constructor
            
$obj->inject($rawData);
            
$result[] = $obj;
        }
        return 
$result;
    }
}
?>

Note: This is a very simple example, and I am aware that there are other (better) ways to do this.
Oliver Anan

darkmantis at cybershade dot org (2011-10-13 09:25:36)

This may be irrelevant to you, but I just had an idea about ‘abstract’ classes and the ‘final’ keyword. If you declare a class as abstract and the constructor of that class as final, then the extending class will not work:

<?php
abstract class newClass{
    final public function 
__construct(){
        echo 
'You failed xD';
    }    
}

class 
MyClass extends newClass{
    public function 
__construct(){
        echo 
'Will this work?';
    }
    
    public static function 
myFunc(){
        echo 
'FooBar';
    }
}

$init = new MyClass();
$init::myFunc();
?>

And that will return :
Fatal error: Cannot override final method newClass::__construct() in C:\wamp\Projects\BMPortal\public_html\newPHPClass.php on line 16

joelhy (2011-05-31 19:27:48)

The documentation says: "It is not allowed to create an instance of a class that has been defined as abstract.". It only means you cannot initialize an object from an abstract class. Invoking static method of abstract class is still feasible. For example:
<?php
abstract class Foo
{
    static function 
bar()
    {
        echo 
"test\n";
    }
}

Foo::bar();
?>

Adrian N (2011-05-02 04:10:53)

By their nature, although sometimes they may look quite similar, abstract classes and class interfaces serve very distinct purposes.
The interface of a class is meant as a tool for the "user" of that class. An interface is a public presentation for the class, and it should advertise, to anyone considering to use it, what methods and constants are available and accessible from the outside. So, as it name suggests, it always sits between the user and the class implementing it.
On the other hand, an abstract class is a tool aimed at helping the "implementor" of the classes that extend it. It is an infrastructure that can impose restrictions and guidelines about what the concrete classes should look like. From a class design perspective, abstract classes are more architecturally important than interfaces. In this case, the implementor sits between the abstract class and the concrete one, building the latter on top of the former.

a dot tsiaparas at watergate dot gr (2011-03-26 15:57:02)

Abstraction and interfaces are two very different tools. The are as close as hammers and drills. Abstract classes may have implemented methods, whereas interfaces have no implementation in themselves.
Abstract classes that declare all their methods as abstract are not interfaces with different names. One can implement multiple interfaces, but not extend multiple classes (or abstract classes).
The use of abstraction vs interfaces is problem specific and the choice is made during the design of software, not its implementation. In the same project you may as well offer an interface and a base (probably abstract) class as a reference that implements the interface. Why would you do that?
Let us assume that we want to build a system that calls different services, which in turn have actions. Normally, we could offer a method called execute that accepts the name of the action as a parameter and executes the action.
We want to make sure that classes can actually define their own ways of executing actions. So we create an interface IService that has the execute method. Well, in most of your cases, you will be copying and pasting the exact same code for execute.
We can create a reference implemention for a class named Service and implement the execute method. So, no more copying and pasting for your other classes! But what if you want to extend MySLLi?? You can implement the interface (copy-paste probably), and there you are, again with a service. Abstraction can be included in the class for initialisation code, which cannot be predefined for every class that you will write.
Hope this is not too mind-boggling and helps someone. Cheers,
Alexios Tsiaparas

designbyjeeba at gmail dot com (2010-12-26 06:29:22)

Please be aware of the visibility of the parent fields. If the fields are private, then you are not going to see those fields in their childrens. Its basic OOP, but can be problematic sometimes.

bishop (2010-07-28 10:36:02)

Incidentally, abstract classes do not need to be base classes:

<?php
class Foo {
    public function 
sneeze() { echo 'achoooo'; }
}

abstract class 
Bar extends Foo {
    public abstract function 
hiccup();
}

class 
Baz extends Bar {
    public function 
hiccup() { echo 'hiccup!'; }
}

$baz = new Baz();
$baz->sneeze();
$baz->hiccup();
?>

mbajoras at gmail dot com (2009-12-31 23:59:14)

Here's an example that helped me with understanding abstract classes. It's just a very simple way of explaining it (in my opinion). Lets say we have the following code:

<?php
class Fruit {
    private 
$color;
    
    public function 
eat() {
        
//chew
    
}
    
    public function 
setColor($c) {
        
$this->color $c;
    }
}

class 
Apple extends Fruit {
    public function 
eat() {
        
//chew until core
    
}
}

class 
Orange extends Fruit {
    public function 
eat() {
        
//peel
        //chew
    
}
}
?>

Now I give you an apple and you eat it.

<?php
$apple 
= new Apple();
$apple->eat();
?>

What does it taste like? It tastes like an apple. Now I give you a fruit.

<?php
$fruit 
= new Fruit();
$fruit->eat();
?>

What does that taste like??? Well, it doesn't make much sense, so you shouldn't be able to do that. This is accomplished by making the Fruit class abstract as well as the eat method inside of it.

<?php
abstract class Fruit {
    private 
$color;
    
    abstract public function 
eat();
    
    public function 
setColor($c) {
        
$this->color $c;
    }
}
?>

Now just think about a Database class where MySQL and PostgreSQL extend it. Also, a note. An abstract class is just like an interface, but you can define methods in an abstract class whereas in an interface they are all abstract.

nathan dot vorbei dot tech at gmail dot com (2009-11-16 22:55:50)

"additionally, these methods must be defined with the same (or a less restricted) visibility."

The words were not restricted in abstract class but also normal classes,
the method in child Class which overwrites the parent Class can also change the the visibility of the method to same or less restricted.
for example:
<?php
class ClassOne {
    protected static 
$staticone 'nathan';
    protected function 
changestaticone() {
        return 
self::$staticone 'john';
    }
}

class 
ClassTwo extends ClassOne {
    public function 
changestaticone() {
        return 
self::$staticone 'Alexey';
    }

$classtwo = new ClassTwo();
echo 
$classtwo->changestaticone();

pete at surfaceeffect dot com (2009-10-13 02:49:34)

One fairly important difference between php's abstract functions and, say, Java, is that php does not specify the return type in any way - or indeed whether there has to be one.

<?php public abstract function square($number); ?>

could be implemented by...

<?php
public function square($number) {
   return 
$number*$number;
}
?>

or 

<?php
public function square($number) {
   print (
$number*$number);
}
?>

So you need to take care that incompatibilities don't arise due to not returning the right kind of value and this is not enforced in any way.

Cheese Doodle (2009-09-22 16:13:37)

There isn't really that much of a great hurdle in understanding these things, there really isn't.
If you're defining a new class that is abstract, it means that you can make some non-abstract functions that you can use to define the general underlying behavior of that class along side abstract ones.
In interfaces, you can't do that since functions defined therewithin cannot have a body.
Abstract functions you use for classes that must define more specific behavior when "extending" your class.
So for a crude example - define by your non-abstract functions how that particular object (which may be part of a larger class hierarchy) would store and process it's data in SQL, XML, etc.
Then define abstract functions which allow someone implementing that class to specifically manipulate the data that is to be stored. Then require a format which this data must be returned in, and then in your non-abstract functions call those functions on destruction, in normal runtime, and so on.
Again, non-abstract functions, or even another class could implement the finer points of ensuring that data is in the correct format, and so on, ad infinitum.
It isn't too much of a reach to say that if you used a normal class instead of an abstract class, then there isn't much intrinsic requirement between the two classes.
Assuming that you wanted the functions to use each-others functions and you'd need to use them specifically by name, you'd have to write some code which checked to see -- lamely using function_exists() and other lamery -- if that class has the function you require for interoperability, when you could avoid all possible confusion and headaches by simply using the right tool for the job.
And reading a decent OOP book.

Kiam (2009-08-01 12:04:49)

The person - student - employee is the classic example where the interfaces are more appropriate.
It is true that students, and employees are persons, but a person can be both a student, and an employee.

<?php
class Person {
  
// Properties for Person objects.
}

interface 
IStudent {
  
// ...
}

interface 
IEmployee {
  
// ...
}

class 
Student implements IStudent extends Person {
  
// ...
}

class 
StudentEmployee implements IStudentIEmployee extends Person {
  
// ...
}
?>

eeescalona (2008-06-02 21:04:28)

here is a real world example of abstract using:

a (abstract) person class
a student and an employee final class, which extends person class.

simple theory is that both student and employee is an extension of the person class.  the difference lies on which table the data is written on, and what other pre processing (ie mandatory field checking, type checking, etc.) needed before writing each of the classes.

codes:

<?php

abstract class person {
    
    abstract protected function 
write_info();
    
    public 
$LastName;
    public 
$FirstName;
    public 
$BirthDate;
    
    public function 
get_Age($today=NULL){
        
//age computation function
    
}
}

final class 
employee extends person{
    public 
$EmployeeNumber;
    public 
$DateHired;

    public function 
write_info(){
        echo 
"Writing "$this->LastName "'s info to emloyee dbase table";    
        
//ADD unique mandatory checking unique to EMPLOYEE ONLY
        //actual sql codes here
    
}
}

final class 
student extends person{
    public 
$StudentNumber;
    public 
$CourseName;
    
    public function 
write_info(){
        echo 
"Writing "$this->LastName "'s info to student dbase table";
        
//ADD unique mandatory checking unique to STUDENT ONLY
        //actual sql codes here
    
}
}

///----------
$personA = new employee;
$personB = new student;

$personA->FirstName="Joe";
$personA->LastName="Sbody";

$personB->FirstName="Ben";
$personB->LastName="Dover";

$personA->write_info();
?>

OUTPUT:Writing Sbody's info to emloyee dbase table

keithjfrank at gmail dot com (2008-05-13 01:19:02)

While building my database class, I came across something I didn't see any documentation on...
abstract class db
{
abstract protected function prepareSelect();
}
class dbPlugin extends db
{
/**
* Prepare Select
* Populates $this->currentQuery with MySQL formatted SELECT query.
*
* @param string Fields to retrieve
* @param string Table from which fields will be selected
* @param string Optional WHERE restriction
**/
protected function prepareSelect( $fields, $table, $where = NULL )
{
$this->currentQuery .= "SELECT {$fields} FROM {$this->dbSettings['sqlPrefix']}{$table}";

if ( $where !== NULL )
{
$this->currentQuery .= " WHERE {$where}";
}
}
}
While executing the script I was greeted with: Fatal error: Declaration of dbPlugin::prepareSelect() must be compatible with that of db::prepareSelect() in [...]\includes\plugins\dbMySQL.php on line 209
The fix? Adding the same expected variables to the parent abstract method.
abstract class db
{
abstract protected function prepareSelect( $fields, $table, $where );
}
I am unsure as to whether this is common knowledge or not, but I figured I would share to ease someone else's frustration while figuring out what was going awry. :)

ironiridis at gmail dot com (2008-03-27 13:56:30)

Just one more time, in the simplest terms possible:

An Interface is like a protocol. It doesn't designate the behavior of the object; it designates how your code tells that object to act. An interface would be like the English Language: defining an interface defines how your code communicates with any object implementing that interface.

An interface is always an agreement or a promise. When a class says "I implement interface Y", it is saying "I promise to have the same public methods that any object with interface Y has".

On the other hand, an Abstract Class is like a partially built class. It is much like a document with blanks to fill in. It might be using English, but that isn't as important as the fact that some of the document is already written.

An abstract class is the foundation for another object. When a class says "I extend abstract class Y", it is saying "I use some methods or properties already defined in this other class named Y".

So, consider the following PHP:
<?php
class implements { } // this is saying that "X" agrees to speak language "Y" with your code.

class extends { } // this is saying that "X" is going to complete the partial class "Y".
?>

You would have your class implement a particular interface if you were distributing a class to be used by other people. The interface is an agreement to have a specific set of public methods for your class.

You would have your class extend an abstract class if you (or someone else) wrote a class that already had some methods written that you want to use in your new class.

These concepts, while easy to confuse, are specifically different and distinct. For all intents and purposes, if you're the only user of any of your classes, you don't need to implement interfaces.

sneakyimp at hotmail dot com (2007-10-09 17:05:57)

Ok...the docs are a bit vague when it comes to an abstract class extending another abstract class.  An abstract class that extends another abstract class doesn't need to define the abstract methods from the parent class.  In other words, this causes an error:

<?php
abstract class class1 {
  abstract public function 
someFunc();
}
abstract class 
class2 extends class1 {
  abstract public function 
someFunc();
}
?>

Error: Fatal error: Can't inherit abstract function class1::someFunc() (previously declared abstract in class2) in /home/sneakyimp/public/chump.php on line 7

However this does not:

<?php
abstract class class1 {
  abstract public function 
someFunc();
}
abstract class 
class2 extends class1 {
}
?>

An abstract class that extends an abstract class can pass the buck to its child classes when it comes to implementing the abstract methods of its parent abstract class.

eamon at gizzle dot co dot uk Eamon Straughn (2007-07-20 16:20:19)

Sometimes I wonder. PHP needs to be pushed to its limits and below everyone fails to understand what an interface is and what abstraction is. So let me make it extremely clear as I have many languages under my belt.

Interfaces are in general WYSIWYG implementations of logic which in PHP are not accessible like in other languages like Java \ ASP.NET where you don't have to access the class itself...however in future I hope PHP does give us this functionality. Interfaces in PHP only define public functions without any basic or core functionality therefore making it lesser a friend to PROs from OOP && OOD backgrounds.

Instead Abstraction in PHP is perfered as this allows your objects a core with the ability to define different levels of access to methods | variables | constants. Although publicly allowing access to variables (to me) | (to official \ senior programmers) defeats the whole idea of OO. Abstraction allows the keywords of final which is very important to me as I can have many child objects of objects and of child objects.

Thus knowing the difference helps with your choosen style but if your really looking to make an application with Abstraction I would always suggest using an Abstract Class instead of Interfaces as Interfaces are limited and provides no functionality and is a waste of bytes on your hard drive.

The below is an example of Abstraction used in an automated system.

<?php
Abstract Class events
{
    protected 
$priority;
    protected 
$message;
    protected 
$environment;
    protected 
$syslog;
    protected 
$config;
    protected 
$global;
    protected 
$classes;
    protected 
$super;
        
  public function 
__construct(array &$config)
    {
        
$this->config $config;
    }
    
    abstract protected function 
writeToDatabase(Environment &$environment);
    abstract protected function 
writeToSystem(Environment &$environment);
    abstract protected function 
writeToEmail(Environment &$environment);
    abstract protected function 
writeToMobile(Environment &$environment);
    abstract public function 
execute(&$class$method$args);
    
    protected function 
environment(Exception &$object) {
        
$this->super =& new Environment($object$this->config);
        
$this->global $this->super->env();
        
$this->global $this->global['environment'];
        return 
$this->super;
    }
    
  public function 
__destruct()
  {
        unset(
$this);
  }
}
?>

pierre at pamdata dot com (2007-06-25 18:25:34)

I love examples.
This example will let you see that an Interface and an Astract Class are two different entities.

Just go and read the Object Interface section at :
http://www.php.net/manual/en/language.oop5.interfaces.php

and look at this example

<?php
/*
* A Very simple example to understand why we should use ABSRACT CLASSES.
* This abstract class contains  2 methods : 1 abstract and 1 common methods.
*
*/
abstract class Shape
{
    
# Let's assume a shape will always have a base and a height
    
protected  $base;
    protected 
$height;
    
    
#This function can be the same for both classes  'Triangle' and 'Rectangle'
    
public function getValue($base,$height)
    {
        
$this->base $base;
        
$this->height $height;
    }
    
    
# This might be different for each class of shape, because each Surface is calculated by a different formula ( St = b*h/2  and  Sr = b*h)
    
abstract public function surface();
}

class 
Triangle extends Shape 
{
    
# s = b*h/2
    
public function surface(){
        return 
round((($this->base)*($this->height)/2),2);
    }
}

class 
Rectangle extends Shape 
{
    
# s = b*h
    
public function surface(){
        return 
round((($this->base)*($this->height)),2);
    }
}

$r = new Rectangle();
$r->getValue(15,3);
echo 
$r->surface() ."\n";   # echo 45

$t = new Triangle();
$t->getValue(15,3);
echo 
$t->surface() ."\n";   # echo 22.5

?>

joebert (2007-06-24 04:09:17)

I don't agree with jfkallens' last comparison between Abstract Classes & Object Interfaces completely.
In an Abstract Class, you can define how some methods work, where as in an Object Interface you can not.
An Object Interface is essentually nothing but a list of function names that a class must define if the class implements that interface.
An Abstract Class is essentually a prototype which hints towards what extending classes should be doing.
An Abstract Class can also be thought of as a Base Class that provides some basic functionality, & also defines a built-in Object Interface that all extending classes will implement.
So, an Object Interface is really a built-in part of an Abstract Class.

david at mr-t dot nl (2006-07-25 08:27:20)

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!

rasto_klc (at) yahoo (dot) obvious (2005-12-28 13:27:00)

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 (2005-12-02 09:38:51)

<?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) {
}

易百教程