第19章 类与对象(PHP5)之九:模式(Patterns)
模式是最好的实践和设计的描述方法。它给普通的编程问题展示一个可变的解决方案。
工厂模式(Factory)
工厂模式允许在运行的时间实例化一个对象。自从工厂模式命名以来,制造一个对象是可能的。
例子 19-23.工厂方法 (Factory Method)
单模式适用于需要一个类的单独接口的情况。最普通的例子是数据库连接。这个模式的实现
允许程序员构造一个通过许多其他对象轻松地访问的单独接口。
例子 19-24.单模式函数(Singleton Function)
工厂模式(Factory)
工厂模式允许在运行的时间实例化一个对象。自从工厂模式命名以来,制造一个对象是可能的。
例子 19-23.工厂方法 (Factory Method)
复制PHP内容到剪贴板
在类中允许定义一个驱动器在不工作时被加载的方法。如果类例子是一个数据库抽象类,可以象如下这样加载一个MySQL和SQLite驱动
PHP代码:
<?php
class Example
{ public static function factory($type)//The factory method
{ if (include_once 'Drivers/'.$type.'.php')
{ $classname = 'Driver_' . $type;
return new $classname;
}else{ throw new Exception ('Driver not found'); }
}
}
?>
复制PHP内容到剪贴板
单独模式(Singleton)
PHP代码:
<?php
$mysql = Example::factory('MySQL'); // Load a MySQL Driver
$sqlite = Example::factory('SQLite'); // Load a SQLite Driver
?>
单模式适用于需要一个类的单独接口的情况。最普通的例子是数据库连接。这个模式的实现
允许程序员构造一个通过许多其他对象轻松地访问的单独接口。
例子 19-24.单模式函数(Singleton Function)
复制PHP内容到剪贴板
允许类实例的一个单独接口被重新获得。
PHP代码:
<?php
class Example
{ // Hold an instance of the class
private static $instance;
private function __construct()//A private constructor;prevents direct creation of object
{ echo 'I am constructed'; }
public static function singleton()// The singleton method
{ if (!isset(self::$instance))
{ $c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
// Example method
public function bark() { echo 'Woof!'; }
// Prevent users to clone the instance
public function __clone(){ trigger_error('Clone is not allowed.',E_USER_ERROR); }
}
?>
复制PHP内容到剪贴板
PHP代码:
<?php
$test = new Example; // This would fail because the constructor is private
$test = Example::singleton();// This will always retrieve a single instance of the class
$test->bark();
$test_clone = clone($test); // This will issue an E_USER_ERROR.
?>
第19章 类与对象(PHP5) 之十:魔法方法(Magic Methods)
函数名__construct, __destruct (注意构造函数和析构函数), __call, __get, __set, __isset, __unset (注意重载), __sleep, __wakeup, __toString, __set_state, __clone and __autoload是PHP类里边的魔法函数.
函数名 __construct, __destruct(注意构造函数和析构函数), __call, __get, __set, __isset, __unset (see 注意重载), __sleep, __wakeup, __toString, __set_state, __clone and __autoload在PHP类里是魔术的.在任何类里你不能用这些名字给函数命名除非你想与它们的魔术功能性相关联。
注意: PHP储量将所有用__开始的函数名作为魔术函数。推荐地,在PHP里不能用__做函数名除非你想用文件证明是魔术函数。
__sleep()和__wakeup()
serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。
使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。
相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。
使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。
例子 19-25. Sleep and wakeup
复制PHP内容到剪贴板
PHP代码:
<?php
class Connection
{ protected $link;
private $server, $username, $password, $db;
public function __construct($server, $username, $password, $db)
{ $this->server = $server;
$this->username = $username;
$this->password = $password;
$this->db = $db;
$this->connect();
}
private function connect()
{ $this->link = mysql_connect($this->server, $this->username, $this->password);
mysql_select_db($this->db, $this->link);
}
public function __sleep() { mysql_close($this->link); }
public function __wakeup() { $this->connect(); }
}
?>
__toString
__toString方法允许一个类决定当它被修改为string类型时是如何起作用的。
例子 19-26.Simple example
复制PHP内容到剪贴板
PHP代码:
<?php
class TestClass// Declare a simple class
{ public $foo;
public function __construct($foo){ $this->foo = $foo; }
public function __toString() { return $this->foo; }
}
$class = new TestClass('Hello');
echo $class;
?>
上例将输出:Hello
__toString方法将只在使用echo()和print()直接地组合时被调用是一个有效的注释方法。
例子 19-27. Cases where __toString is called
复制PHP内容到剪贴板
PHP代码:
<?php
echo $class; //__toString called
echo 'text',$class; //__toString called (still a normal parameter for echo)
echo 'text'.$class; // __toString not called (concatenation operator used first)
echo (string)$class; //__toString not called (cast to string first)
echo "text $class";//__toString not called (cast to string first)
?>
__set_state
从PHP 5.1.0开始static方法是通过var_export()函数来访问类接口的。这个方法的唯一参数是一个包含属性出口的以为array(‘property’=value,…)形式的数组
第19章:类与对象(PHP5)之十一:最终关键字(Final Keyword)
PHP5引入了最终关键字,防止子类使用final从一个重要的方法做定义的前缀。如果类本身已经被定义为final,类将不能被扩展。
例子 19-28.Final方法实例
例子 19-28.Final方法实例
复制PHP内容到剪贴板
例子 19-29. Final 类实例
PHP代码:
<?php
class BaseClass
{ public function test()
{
echo "BaseClass::test() called\n";
}
final public function moreTesting()
{
echo"BaseClass::moreTesting() called\n";
}
}
class ChildClass extends BaseClass
{
public function moreTesting()
{
echo "ChildClass::moreTesting() called\n";
}
}
//Results in Fatal error:Cannot override final method BaseClass::moreTesting()
?>
复制PHP内容到剪贴板
[
本帖最后由 forest 于 2006-5-4 18:29 编辑 ]
PHP代码:
<?php
final class BaseClass
{ public function test()
{
echo "BaseClass::test() called\n";
}
//Here it doesn't matter if you specify the function as final or not
final public function moreTesting()
{
echo"BaseClass::moreTesting() called\n";
}
}
class ChildClass extends BaseClass { }
//Results in Fatal error:Class ChildClass may not inherit from final class (BaseClass)
?>
第19章 类与对象(PHP5)之十二:对象克隆(Object cloning)
通过完全地复制属性创建一个对象的拷贝不是通常想要的行为。需求的一个好的实例适合于拷贝构造函数,
如果有一个对象描述一个GTK窗口和对象保存这个GTK窗口的资源,当你创建一个副本,你或许想创建一个相同的属性新窗口使用和保存新对象资源的新窗口。另一个例子是当你复制父对象时如果保存一个引用给另一个对象,你想创建其他类的一个新实例来分开拷贝所属的复制品。一个对象的拷贝是使用clone关键字来创建的(如果可能的话可以调用对象的__clone()方法),一个对象的__clone()方法不能被直接声明。
例子 19-30. 克隆一个对象
如果有一个对象描述一个GTK窗口和对象保存这个GTK窗口的资源,当你创建一个副本,你或许想创建一个相同的属性新窗口使用和保存新对象资源的新窗口。另一个例子是当你复制父对象时如果保存一个引用给另一个对象,你想创建其他类的一个新实例来分开拷贝所属的复制品。一个对象的拷贝是使用clone关键字来创建的(如果可能的话可以调用对象的__clone()方法),一个对象的__clone()方法不能被直接声明。
复制PHP内容到剪贴板
当一个对象被克隆时,PHP5将执行一个所有对象的属性的浅拷贝。任何对其它变量引用的属性将只保留引用。如果一个__clone()方法被定义,然后重新创建一个对象的克隆方法来允许任何必需的属性当它需要被改变时调用。
PHP代码:
$copy_of_object = clone $object;
例子 19-30. 克隆一个对象
复制PHP内容到剪贴板
上例将输出:
PHP代码:
<?php
class SubObject
{ static $instances = 0;
public $instance;
public function __construct(){ $this->instance=++self::$instances; }
public function __clone() { $this->instance=++self::$instances; }
}
class MyCloneable
{ public $object1;
public $object2;
function __clone()
{
$this->object1=clone($this->object1);//Force a copy of this->object,otherwise it will point to same object.
}
}
$obj = new MyCloneable();
$obj->object1 = new SubObject();
$obj->object2 = new SubObject();
$obj2 = clone $obj;
print("Original Object:\n");
print_r($obj);
print("Cloned Object:\n");
print_r($obj2);
?>
复制内容到剪贴板
代码:
Original Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 1
)
[object2] => SubObject Object
(
[instance] => 2
)
)
Cloned Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 3
)
[object2] => SubObject Object
(
[instance] => 2
)
)
第19章:类与对象(PHP5)之十三:对象比较(Comparing objects)
在PHP5中,对象的比较比PHP4中的更复杂和更协调的期望的一个面向对象语言(倒不是说PHP5是这样的一门语言)。当使用比较操作符(==),对象变量以一种简单的方式被比较。也就是:如果它们具有相同的属性和值,两个对象的实例是相等,并且是同一个类的实例。
另一方面,当使用恒等式操作符(===)时,对象变量当且仅当它们引用同一个类的同一个实例时是相同的
一个例子就可以阐明这些规则
例子 19-31.PHP5中的对象比较实例
另一方面,当使用恒等式操作符(===)时,对象变量当且仅当它们引用同一个类的同一个实例时是相同的
一个例子就可以阐明这些规则
例子 19-31.PHP5中的对象比较实例
复制PHP内容到剪贴板
上例将输出:
PHP代码:
<?php
function bool2str($bool)
{ if ($bool===false) { return 'FALSE'; }
else { return 'TRUE'; }
}
function compareObjects(&$o1, &$o2)
{ echo 'o1 == o2 : '. bool2str($o1 == $o2) . "\n";
echo 'o1 != o2 : ' . bool2str($o1 != $o2) . "\n";
echo 'o1 === o2 : ' . bool2str($o1 === $o2) . "\n";
echo 'o1 !== o2 : ' . bool2str($o1 !== $o2) . "\n";
}
class Flag
{ public $flag;
function Flag($flag = true) { $this->flag = $flag; }
}
class OtherFlag
{ public $flag;
function OtherFlag($flag = true) { $this->flag = $flag; }
}
$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();
echo "Two instances of the same class\n";
compareObjects($o, $p);
echo "\nTwo references to the same instance\n";
compareObjects($o, $q);
echo "\nInstances of two different classes\n";
compareObjects($o, $r);
?>
复制内容到剪贴板
代码:
Two instances of the same class
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE
Two references to the same instance
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE
Instances of two different classes
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
第19章 类与对象(PHP5)之十四:映射(反射)Reflection
介绍(Introduction)
PHP 5与一个API完全映射来以增加反向工程师类,接口,函数和方法的效率(性能)并加以扩展。另外, API映射并且为函数,类和方法提供获取文档注释的方法。
API映射是对Zend引擎一个面向对象的扩展。包括以下类:
复制PHP内容到剪贴板
PHP代码:
<?php
class Reflection { }
interface Reflector { }
class ReflectionException extends Exception { }
class ReflectionFunction implements Reflector { }
class ReflectionParameter implements Reflector { }
class ReflectionMethod extends ReflectionFunction { }
class ReflectionClass implements Reflector { }
class ReflectionObject extends ReflectionClass { }
class ReflectionProperty implements Reflector { }
class ReflectionExtension implements Reflector { }
?>
注:为了详细了解这些类,请看下一章。 如果我们将执行如下例子的代码:
例子 19-32.API映射的基本用法
复制PHP内容到剪贴板
PHP代码:
<?php
Reflection::export(new ReflectionClass('Exception'));
?>
上例将输出:
复制内容到剪贴板
代码:
Class [ <internal> class Exception ] {
- Constants [0] { }
- Static properties [0] { }
- Static methods [0] { }
- Properties [6] {
Property [ <default> protected $message ]
Property [ <default> private $string ]
Property [ <default> protected $code ]
Property [ <default> protected $file ]
Property [ <default> protected $line ]
Property [ <default> private $trace ]
}
- Methods [9] {
Method [ <internal> final private method __clone ] { }
Method [ <internal> <ctor> public method __construct ] {
- Parameters [2] {
Parameter #0 [ <required> $message ]
Parameter #1 [ <required> $code ]
}
}
Method [ <internal> final public method getMessage ] { }
Method [ <internal> final public method getCode ] { }
Method [ <internal> final public method getFile ] { }
Method [ <internal> final public method getLine ] { }
Method [ <internal> final public method getTrace ] { }
Method [ <internal> final public method getTraceAsString ] { }
Method [ <internal> public method __toString ] { }
}
}
异常映射(ReflectionException)
ReflectionException 扩展标准异常并由API映射抛出。引入了非特定方法或属性。
映射函数(ReflectionFunction)
ReflectionFunction类允许你反向设计函数。
复制PHP内容到剪贴板
PHP代码:
<?php
class ReflectionFunction implements Reflector
{
final private __clone()
public object __construct(string name)
public string __toString()
public static string export()
public string getName()
public bool isInternal()
public bool isUserDefined()
public string getFileName()
public int getStartLine()
public int getEndLine()
public string getDocComment()
public array getStaticVariables()
public mixed invoke(mixed* args)
public mixed invokeArgs(array args)
public bool returnsReference()
public ReflectionParameter[] getParameters()
public int getNumberOfParameters()
public int getNumberOfRequiredParameters()
}
?>
注:getNumberOfParameters()和getNumberOfRequiredParameters()在PHP5.0.3中增加,而invokeArgs()是在PHP5.1.0中增加。
为内省一个函数,您必须首先创建ReflectionFunction 类的一个实例。您可以随后访问这个实例中的任何上述方法。
例子 19-33. 使用ReflectionFunction 类
复制PHP内容到剪贴板
PHP代码:
<?php
/** A simple counter
* @return int */
function counter()
{ static $c = 0;
return $c++;
}
// Create an instance of the Reflection_Function class
$func = new ReflectionFunction('counter');
// Print out basic information
printf(
"===> The %s function '%s'\n".
" declared in %s\n".
" lines %d to %d\n",
$func->isInternal() ? 'internal' : 'user-defined',
$func->getName(),
$func->getFileName(),
$func->getStartLine(),
$func->getEndline()
);
// Print documentation comment
printf("--->Documentation:\n%s\n",var_export($func->getDocComment(),1));
if ($statics=$func->getStaticVariables())//Print static variables if existant
{ printf("--->Static variables:%s\n",var_export($statics,1)); }
printf("--->Invokation results in:");//Invoke the function
var_dump($func->invoke());
//you may prefer to use the export() method
echo "\nReflectionFunction::export() results:\n";
echo ReflectionFunction::export('counter');
?>
注:方法invoke()通过象call_user_func()这样的函数接受自变量的一个变化的数值。
映射参数 (ReflectionParameter)
ReflectionParameter类取回一个函数或方法的参数的信息。
复制PHP内容到剪贴板
PHP代码:
<?php
class ReflectionParameter implements Reflector
{
final private __clone()
public object __construct(string name)
public string __toString()
public static string export()
public string getName()
public bool isPassedByReference()
public ReflectionClass getClass()
public bool isArray()
public bool allowsNull()
public bool isOptional()
public bool isDefaultValueAvailable()
public mixed getDefaultValue()
}
?>
注: 在PHP 5.0.3中增加了getDefaultValue(), isDefaultValueAvailable()和isOptional(),而isArray()则是在PHP5.1.0中增加的。
为内省函数参数,你必须首先创建ReflectionFunction或ReflectionMethod类的一个实例,然后用getParameters()方法来返回一个数组型参数。
例子 19-34. Using the ReflectionParameter class
复制PHP内容到剪贴板
PHP代码:
<?php
function foo($a, $b, $c) { }
function bar(Exception $a, &$b, $c) { }
function baz(ReflectionFunction $a, $b = 1, $c = null) { }
function abc() { }
//通过命令行用给定的参数创建ReflectionFunction的一个实例
$reflect = new ReflectionFunction($argv[1]);
echo $reflect;
foreach ($reflect->getParameters() as $i => $param)
{ printf( "-- Parameter #%d: %s {\n".
" Class: %s\n".
" Allows NULL: %s\n".
" Passed to by reference: %s\n".
" Is optional?: %s\n".
"}\n",
$i,
$param->getName(),
var_export($param->getClass(), 1),
var_export($param->allowsNull(), 1),
var_export($param->isPassedByReference(), 1),
$param->isOptional() ? 'yes' : 'no');
}
?>
映射类(ReflectionClass)
ReflectionClass类允许你反向设计类。
复制PHP内容到剪贴板
PHP代码:
<?php
class ReflectionClass implements Reflector
{ final private __clone()
public object __construct(string name)
public string __toString()
public static string export()
public string getName()
public bool isInternal()
public bool isUserDefined()
public bool isInstantiable()
public bool hasConstant(string name)
public bool hasMethod(string name)
public bool hasProperty(string name)
public string getFileName()
public int getStartLine()
public int getEndLine()
public string getDocComment()
public ReflectionMethod getConstructor()
public ReflectionMethod getMethod(string name)
public ReflectionMethod[] getMethods()
public ReflectionProperty getProperty(string name)
public ReflectionProperty[] getProperties()
public array getConstants()
public mixed getConstant(string name)
public ReflectionClass[] getInterfaces()
public bool isInterface()
public bool isAbstract()
public bool isFinal()
public int getModifiers()
public bool isInstance(stdclass object)
public stdclass newInstance(mixed* args)
public ReflectionClass getParentClass()
public bool isSubclassOf(ReflectionClass class)
public array getStaticProperties()
public mixed getStaticPropertyValue(string name [, mixed default])
public void setStaticPropertyValue(string name, mixed value)
public array getDefaultProperties()
public bool isIterateable()
public bool implementsInterface(string name)
public ReflectionExtension getExtension()
public string getExtensionName()
}
?>
注:PHP5.1.0中增加了hasConstant(), hasMethod(), hasProperty(), getStaticPropertyValue()和 setStaticPropertyValue()。