Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 网站建设 > PHP > 转PHP中国手册类与对象翻译部份
【标  题】:转PHP中国手册类与对象翻译部份
【关键字】:PHP
【来  源】:http://www.cublog.cn/u/10599/showart.php?id=144941

转PHP中国手册类与对象翻译部份

Your Ad Here
第18章. 类与对象(PHP 4)
1.类
类是变量与作用于这些变量的函数的集合。使用下面的语法定义一个类:
<?php
class Cart
{   var $items;  //购物车中的物品
    function add_item($artnr,$num) //将$num个$artnr物品加入购物车
     {   $this->items[$artnr] += $num;  }
    function remove_item($artnr,$num) //将$num个$artnr物品从购物车中取出
    {    if ($this->items[$artnr] > $num)
         {   $this->items[$artnr] -= $num;
            return true;
        } elseif ($this->items[$artnr] == $num) {
            unset($this->items[$artnr]);
            return true;
        } else {   return false;   }
    }
}
?>
上面的例子定义了一个 Cart 类,这个类由购物车中的商品构成的数组和两个用于从购物车中添加和删除商品的函数组成。
                                     警告:
不能将一个类的定义分割到多个文件中。也不能将一个类的定义分割到多个PHP块中,除非该分割是在一个方法声明内部。以下用法将不起作用:
<?phpclass
test {
?>
<?php
    function test()
{   print 'OK';
}}?>
但是以下用法是可以的:
<?phpclass
test {   
     function test()
{?>
<?php 
    print 'OK'; }  
 } ?>
以下警告仅用于 PHP 4。
                                注意:
1.名称 stdClass 已经被 Zend 使用并保留。不能在 PHP 代码中定义名为 stdClass 的类。
2.函数名 __sleep 和 __wakeup 在 PHP 类中是魔术函数。除非想要与之联系的魔术功能,否则在任何类中都不能以此命名函数。
3.PHP 将所有以 __ 开头的函数名保留为魔术函数。除非想要使用一些见于文档中的魔术功能,否则建议不要在 PHP 中将函数名以 __ 开头。
在 PHP 4 中,var 变量的值只能初始化为常量。用非常量值初始化变量,需要一个初始化函数,该函数在对象被创建时自动被调用。这样一个函数被称之为构造函数(见下面)。
<?php
/* PHP4中不能这样用 */
class Cart
{   var $todays_date = date("Y-m-d");
    var $name = $firstname;
    var $owner = 'Fred ' . 'Jones';
    /* 不过包含有常量的数组可以 */
    var $items = array("VCR", "TV");
}
/* 应该这样进行 */
class Cart
{   var $todays_date;
    var $name;
    var $owner;
    var $items = array("VCR", "TV");
    function Cart()
     {   $this->todays_date = date("Y-m-d");
        $this->name = $GLOBALS['firstname'];
    }
}
?>
类也是一种类型,就是说,它们是实际变量的蓝图。必须用new运算符来创建相应类型的变量。
<?php
$cart = new Cart;
$cart->add_item("10",1);
$another_cart = new Cart;
$another_cart->add_item("0815", 3);
?>
 上述代码创建了两个 Cart 类的对象 $cart 和 $another_cart,对象 $cart 的方法 add_item() 被调用时,添加了 1 件 10 号商品。对于对象 $another_cart,3 件 0815 号商品被添加到购物车中。
$cart 和 $another_cart 都有方法 add_item(),remove_item() 和一个 items 变量。它们都是明显的函数和变量。可以把它们当作文件系统中的某些类似目录的东西来考虑。在文件系统中,可以拥有两个不同的 README.TXT 文件,只要不在相同的目录中。正如从为了根目录访问每个文件需要输入该文件的完整的路径名一样,必须指定需要调用的函数的完整名称:在 PHP 术语中,根目录将是全局名字空间,路径名符号将是 ->。因而,名称 $cart->items 和 $another_cart->items 命名了两个不同的变量。注意变量名为 $cart->items,不是 $cart->$items,那是因为在 PHP 中一个变量名只有一个单独的美元符号。
<?php
$cart->items=array("10"=>1);//正确,只有一个$
$cart->$items=array("10"=>1);//不正确,因为$cart->$items变成了$cart->""
$myvar='items';//正确,但可能不是想要的结果:$cart->$myvar变成了$cart->items
$cart->$myvar=array("10"=>1);
?> 
在定义类的时候,无法得知将使什么名字的对象来访问:在编写 Cart 类时,并不知道之后对象的名称将会命名为 $cart 或者 $another_cart。因而你不能在类中使用 $cart->items。然而为了类定义的内部访问自身的函数和变量,可以使用伪变量 $this 来达到这个目的。$this 变量可以理解为“我自己的”或者“当前对象”。因而 '$this->items[$artnr] += $num' 可以理解为“我自己的物品数组的 $artnr 计数器加 $num”或者“在当前对象的物品数组的 $artnr 计数器加 $num”。
注: 伪变量 $this 通常未定义,如果其所在的方法是被静态调用的话。但这不是个严格规定:如果一个方法被从另一个对象内静态调用的话,则 $this 会被定义。此时 $this 的值是那个发出调用的对象。用下例演示:
<?php
class A
{    function foo()
    {   if (isset($this))
{   echo '$this is defined (';
            echo get_class($this);
            echo ")\n";
        }
         else {  echo "\$this is not defined.\n";  }
    }
}
class B
{   
function bar(){   A::foo();  }
}
$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
 
上例将输出:
$this is defined (a)
$this is not defined.
$this is defined (b)
$this is not defined.
2.继承
通常需要这样一些类,这些类与其它现有的类拥有相同变量和函数。实际上,定义一个通用类用于所有的项目,并且不断丰富这个类以适应每个具体项目将是一个不错的练习。为了使这一点变得更加容易,类可以从其它的类中扩展出来。扩展或派生出来的类拥有其基类(这称为“继承”,只不过没人死)的所有变量和函数,并包含所有派生类中定义的部分。类中的元素不可能减少,就是说,不可以注销任何存在的函数或者变量。一个扩充类总是依赖一个单独的基类,也就是说,不支持多继承。使用关键字“extends”来扩展一个类。
<?php
class Named_Cart extends Cart
{   var $owner;
    function set_owner($name) {  $this->owner = $name;  }
}
?>
上述示例定义了名为 Named_Cart 的类,该类拥有 Cart 类的所有变量和函数,加上附加的变量 $owner 和一个附加函数 set_owner()。现在,以正常的方式创建了一个有名字的购物车,并且可以设置并取得该购物车的主人。而正常的购物车类的函数依旧可以在有名字的购物车类中使用:
<?php
$ncart = new Named_Cart;    //新建一个有名字的购物车
$ncart->set_owner("kris");  //给该购物车命名
print $ncart->owner;        //输出该购物车主人的名字
$ncart->add_item("10", 1);  //(从购物车类中继承来的功能)
?>
这个也可以叫做“父-子”关系。创建一个类,父类,并使用extends来创建一个基于父类的新类:子类。甚至可以使用这个新的子类来创建另外一个基于这个子类的类。
注: 类只有在定义后才可以使用!如果需要类Named_Cart继承类Cart,必须首先定义Cart类。如果需要创建另一个基于Named_Cart类的Yellow_named_cart 类,必须首先定义Named_Cart类。简捷的说:类定义的顺序是非常重要的。
3.构造函数
构造函数是类中的一个特殊函数,当使用new操作符创建一个类的实例时,构造函数将会自动调用。当函数与类同名时,这个函数将成为构造函数。如果一个类没有构造函数,则调用基类的构造函数,如果有的话。
<?php
class Auto_Cart extends Cart

function Auto_Cart() {   $this->add_item ("10", 1);   }
}
?>
上文定义了一个 Auto_Cart 类,即 Cart 类加上一个构造函数,当每次使用“new”创建一个新的 Auto_Cart 类实例时,构造函数将自动调用并将一件商品的数目初始化为“10”。构造函数可以使用参数,而且这些参数可以是可选的,它们可以使构造函数更加有用。为了依然可以不带参数地使用类,所有构造函数的参数应该提供默认值,使其可选。
<?php
class Constructor_Cart extends Cart
{
    function Constructor_Cart($item="10",$num=1){  $this->add_item($item,$num); }
}
$default_cart = new Constructor_Cart; //买些同样的无聊老货
$different_cart = new Constructor_Cart("20", 17); //买些实在货.
?> 
也可以使用 @ 操作符来抑制发生在构造函数中的错误。例如 @new。
<?php
class A
{
    function A() {   echo "I am the constructor of A.<br>\n";   }
     function B()
    {   echo "I am a regular function named B in class A.<br>\n";
        echo "I am not a constructor in A.<br>\n";
    }
}
class B extends A
{
   function C() {  echo "I am a regular function.<br>\n";  }
}
$b = new B; //调用B()作为构造函数
?>
类 A 中的函数 B() 将立即成为类 B 中的构造函数,虽然并不是有意如此。PHP 4 并不关心函数是否在类 B 中定义的,或者是否被继承来的。
                                     注意
PHP 4 不会从派生类的构造函数中自动调用基类的构造函数。恰当地逐次调用上一级的构造函数是用户的责任。
析构函数是一种当对象被销毁时,无论使用了 unset() 或者简单的脱离范围,都会被自动调用的函数。PHP 中没有析构函数。可以用 register_shutdown_function() 来替代模拟大多数析构函数的效果。
4. 作用域分辨运算符(::)
                                     注意
下列内容仅在 PHP 4 及以后版本中有效。
有时,在没有声明任何实例的情况下访问类中的函数或者基类中的函数和变量很有用处。而 :: 运算符即用于此情况。
<?php
class A
{
   function example(){ echo "I am the original function A::example().<br>\n"; }
}
class B extends A
{   function example()
{   echo "I am the redefined function B::example().<br>\n";
        A::example();
  }
}
// A 类没有对象,这将输出 I am the original function A::example().
A::example();
$b = new B; // 建立一个B类的对象
// 这将输出:  I am the redefined function B::example().<br>
              I am the original function A::example().<br>
$b->example();
?>
上面的例子调用了 A 类的函数 example(),但是这里并不存在 A 类的对象,因此不能这样用 $a->example() 或者类似的方法调用 example()。反而我们将 example() 作为一个类函数来调用,也就是说,作为一个类自身的函数来调用,而不是这个类的任何对象。
这里有类函数,但没有类的变量。实际上,在调用函数时完全没有任何对象。因而一个类的函数可以不使用任何对象(但可以使用局部或者全局变量),并且可以根本不使用 $this 变量。
    上面的例子中,类 B 重新定义了函数 example()。A 类中原始定义的函数 example() 将被屏蔽并且不再生效,除非使用 :: 运算符来访问 A 类中的 example() 函数。如:A::example()(实际上,应该写为 parent::example(),下一章介绍该内容)。就此而论,对于当前对象,它可能有对象变量。因此可以在对象函数的内部使用 $this 和对象变量。
5. parent
    户可能会发现自己写的代码访问了基类的变量和函数。如果派生类非常精炼或者基类非常专业化的时候尤其是这样。
    不要用代码中基类文字上的名字,应该用特殊的名字 parent,它指的就是派生类在 extends 声明中所指的基类的名字。这样做可以避免在多个地方使用基类的名字。如果继承树在实现的过程中要修改,只要简单地修改类中 extends 声明的部分。
<?php
    class A
{   function example()
{echo "I am A::example() and provide basic functionality.<br/>\n";}
}
class B extends A
{   function example()
    {   echo "I am B::example() and provide additional functionality.<br />\n";
        parent::example();
    }
}
$b = new B;
$b->example();//这将调用B::example(),而它会去调用A::example()。
?> 
6. 序列化对象 - 会话中的对象
注: 在 PHP 3 中,在序列化和解序列化的过程中对象会失去类的关联。结果的变量是对象类型,但是没有类和方法,因此就没什么用了(就好像一个用滑稽的语法定义的数组一样)。
                                      注意
以下信息仅在 PHP >= 4 中有效。
    serialize() 返回一个字符串,包含着可以储存于 PHP 的任何值的字节流表示。unserialize() 可以用此字符串来重建原始的变量值。用序列化来保存对象可以保存对象中的所有变量。对象中的函数不会被保存,只有类的名称。
    要能够 unserialize() 一个对象,需要定义该对象的类。也就是,如果序列化了 page1.php 中类 A 的对象 $a,将得到一个指向类 A 的字符串并包含有所有 $a 中变量的值。如果要在 page2.php 中将其解序列化,重建类 A 的对象 $a,则 page2.php 中必须要出现类 A 的定义。例如可以这样实现,将类 A 的定义放在一个包含文件中,并在 page1.php 和 page2.php 都包含此文件。
<?php
// classa.inc:
 class A
  {   var $one = 1;
      function show_one() {  echo $this->one;  }
  }
// page1.php:
  include("classa.inc");
  $a = new A;
  $s = serialize($a);
  // 将 $s 存放在某处使 page2.php 能够找到
  $fp = fopen("store", "w");
  fwrite($fp, $s);
  fclose($fp);
// page2.php:
   include("classa.inc"); // 为了正常解序列化需要这一行
  $s = implode("", @file("store"));
  $a = unserialize($s);
  // 现在可以用 $a 对象的 show_one() 函数了
  $a->show_one();?>
   如果在用会话并使用了 session_register() 来注册对象,这些对象会在每个 PHP 页面结束时被自动序列化,并在接下来的每个页面中自动解序列化。基本上是说这些对象一旦成为会话的一部分,就能在任何页面中出现。
    强烈建议在所有的页面中都包括这些注册的对象的类的定义,即使并不是在所有的页面中都用到了这些类。如果没有这样做,一个对象被解序列化了但却没有其类的定义,它将失去与之关联的类并成为 stdClass 的一个对象而完全没有任何可用的函数,这样就很没有用处。
    因此如果在以上的例子中 $a 通过运行 session_register("a") 成为了会话的一部分,应该在所有的页面中包含 classa.inc 文件,而不只是 page1.php 和 page2.php。
7. 魔术函数 __sleep 和 __wakeup
serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。
使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。
相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。
使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。
8. 构造函数中的引用
在构造函数中创建引用可能会导致混淆的结果。本节以教程形式帮助避免问题。
<?php
class Foo
{   function Foo($name)
    {    global $globalref; //在全局数组$globalref中建立一个引用
        $globalref[] = &$this;
        $this->setName($name);  //将名字设定为传递的值
        $this->echoName();//并输出之
    }
    function echoName() {  echo "<br />",$this->name;  }
    function setName($name) {  $this->name = $name;  }
}
?>
下面来检查一下用拷贝运算符= 创建的$bar1和用引用运算符 =& 创建的$bar2 没有区别.
<?php
$bar1 = new Foo('set in constructor');
$bar1->echoName();
$globalref[0]->echoName();
/* 输出:set in constructor
         set in constructor
         set in constructor  */
$bar2 =& new Foo('set in constructor');
$bar2->echoName();
$globalref[1]->echoName();
/* 输出:set in constructor
         set in constructor
         set in constructor  */
?>
    显然没有区别,但实际上有一个非常重要的区别:$bar1 和 $globalref[0] 并没有被引用,它们不是同一个变量。这是因为“new”默认并不返回引用,而返回一个拷贝。
    注: 在返回拷贝而不是引用中并没有性能上的损失(因为 PHP 4 及以上版本使用了引用计数)。相反更多情况下工作于拷贝而不是引用上更好,因为建立引用需要一些时间而建立拷贝实际上不花时间(除非它们都不是大的数组或对象,而其中之一跟着另一个变,那使用引用来同时修改它们会更聪明一些)。
要证明以上写的,看看下面的代码。
<?php
//现在改个名字,你预期什么结果?可能预期$bar1和$globalref[0]二者的名字都改了
$bar1->setName('set from outside');
//但如同前面说的,并不是这样。
$bar1->echoName();
$globalref[0]->echoName();
/* 输出为:set from outside
           set in constructor  */
//现在看看$bar2和$globalref[1]有没有区别
$bar2->setName('set from outside');
//幸运的是它们不但相同,根本就是同一个变量。
//因此$bar2->name和$globalref[1]->name也是同一个变量。
$bar2->echoName();
$globalref[1]->echoName();
/* 输出为:set from outside
           set from outside    */
?>
最后给出另一个例子,试着理解它。
<?php
class A
{
    function A($i)
{    $this->value = $i;
        $this->b = new B($this); //试着想明白为什么这里不需要引用
    }
    function createRef() {    $this->c = new B($this);  }
    function echoValue()
    {    echo "<br/>","class",get_class($this),': ',$this->value;
    }
}
class B
{    function B(&$a) {    $this->a = &$a;   }
    function echoValue()
    {    echo "<br/>","class ",get_class($this),': ',$this->a->value;
    }
}
//试着理解为什么这里一个简单的拷贝会在下面用标出来的行中产生预期之外的结果
$a =& new A(10);
$a->createRef();
$a->echoValue();
$a->b->echoValue();
$a->c->echoValue();
$a->value = 11;
$a->echoValue();
$a->b->echoValue();
$a->c->echoValue();
?>
上例将输出:
class A: 10
class B: 10
class B: 10
class A: 11
class B: 11
class B: 11
9. 对象的比较
在 PHP 4 中,对象比较的规则十分简单:如果两个对象是同一个类的实例,且它们有相同的属性和值,则这两个对象相等。类似的规则还适用与用全等符(===)对两个对象的比较。
如果执行以下范例中的代码:
例子 18-1. PHP 4 中对象比较范例
<?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
{   var $flag;
    function Flag($flag=true) {   $this->flag = $flag;   }
}
class SwitchableFlag extends Flag
{
    function turnOn()  {    $this->flag = true;   }
    function turnOff() {    $this->flag = false;   }
}
$o = new Flag();
$p = new Flag(false);
$q = new Flag();
$r = new SwitchableFlag();
echo "Compare instances created with the same parameters\n";
compareObjects($o, $q);
echo "\nCompare instances created with different parameters\n";
compareObjects($o, $p);
echo "\nCompare an instance of a parent class with one from a subclass\n";
compareObjects($o, $r);
?>
    这和按照比较规则推测的结果一致。当且仅当出自同一个类且属性及其值都相同的对象被认为是相等且完全相同的。即使对于具有对象成分的类,比较的规则也相同。在以下的范例中建立了一个容器类来储存 Flag 对象的一个相关数组。
例子 18-2. PHP 4 中复合对象的比较
<?php
class FlagSet
{    var $set;
   function FlagSet($flagArr = array())
   {    $this->set = $flagArr;   }
   function addFlag($name, $flag) {   $this->set[$name] = $flag;   }
    function removeFlag($name)
    {
      if(array_key_exists($name,$this->set)){unset($this->set[$name]);}
    }
}
$u = new FlagSet();
$u->addFlag('flag1', $o);
$u->addFlag('flag2', $p);
$v = new FlagSet(array('flag1'=>$q, 'flag2'=>$p));
$w = new FlagSet(array('flag1'=>$q));
echo "\nComposite objects u(o,p) and v(q,p)\n";
compareObjects($u, $v);
echo "\nu(o,p) and w(q)\n";
compareObjects($u, $w);
?>
上例将输出:
Composite objects u(o,p) and v(q,p)
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE
u(o,p) and w(q)
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
第19章. 类与对象(PHP 5)
1.前言
PHP 5 引入了新的对象模型(Object Model)。完全重写了 PHP 处理对象的方式,允许更佳性能和更多特性。
2. 基本概念
class
每个类的定义都以关键字 class 开头,后面跟着类名,可以是任何非 PHP 保留字的名字。后面跟着一对花括号,里面包含有类成员和方法的定义。伪变量 $this 可以在当一个方法在对象内部调用时使用。$this 是一个到调用对象(通常是方法所属于的对象,但也可以是另一个对象,如果该方法是从第二个对象内静态调用的话)的引用。看下面例子:
<?php
class A
{  function foo()
    {    if (isset($this))
          {   echo '$this is defined (';
            echo get_class($this);
            echo ")\n";
         } else { echo "\$this is not defined.\n"; }
    }
}
class B
{  
     function bar(){   A::foo(); }
}
$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
上例将输出:
$this is defined (a)
$this is not defined.
$this is defined (b)
$this is not defined.
例子 19-1. 简单的类定义
<?php
class SimpleClass
{   public $var = 'a default value'; //成员声明
    public function displayVar()//方法声明
   {    echo $this->var;
   }
}
?>
new
要创建一个对象的实例,必须创建一个新对象并将其赋给一个变量。当创建新对象时该对象总是被赋值,除非该对象定义了构造函数并且在出错时抛出了一个异常。
例子 19-2. 创建一个实例e
<?php   $instance = new SimpleClass(); ?>
当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。可以用克隆给一个已创建的对象建立一个新实例。
例子 19-3. 对象赋值
<?php
$assigned   =  $instance;
$reference  =& $instance;
$instance->var = '$assigned will have this value';
$instance = null; // $instance and $reference become null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>
上例将输出:
NULL
extends
一个类可以在声明中用 extends 关键字继承另一个类的方法和成员。不能扩展多个类,只能继承一个基类。
被继承的方法和成员可以通过用同样的名字重新声明被覆盖,除非父类定义方法时使用了final关键字。可以通过 parent:: 来访问被覆盖的方法或成员。
例子 19-4. 简单的类继承
<?php
class ExtendClass extends SimpleClass
{// Redefine the parent method
    function displayVar()
    {   echo "Extending class\n";
        parent::displayVar();
    }
}
$extended = new ExtendClass();
$extended->displayVar();
?>
上例将输出:
Extending class
a default value
3. 自动加载对象
很多开发者写面向对象的应用程序时对每个类的定义建立一个 PHP 源文件。一个很大的烦恼是不得不在每个脚本(每个类一个文件)开头写一个长长的包含文件列表。
    在 PHP 5 中,不再需要这样了。可以定义一个 __autoload 函数,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
    注:在__autoload 函数中抛出的异常不能被catch语句块捕获并导致致命错误。
例子 19-5. Autoload 例子
本例尝试分别从 MyClass1.php 和 MyClass2.php 文件中加载 MyClass1 和 MyClass2 类。
<?php
function __autoload($class_name)
{   require_once $class_name.'.php';
}
$obj  = new MyClass1();
$obj2 = new MyClass2();
?> 
4. 构造函数和析构函数
构造函数
void __construct ( [mixed args [,…]])
PHP5允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
    注: 如果子类中定义了构造函数则不会暗中调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用parent::__construct()。
例子 19-6. 使用新标准的构造函数
<?php
class BaseClass
{
   function __construct() {  print "In BaseClass constructor\n";  }
}
class SubClass extends BaseClass {
   function __construct()
   {    parent::__construct();
       print "In SubClass constructor\n";
   }
}
$obj = new BaseClass();
$obj = new SubClass();
?>
为了实现向后兼容性,如果 PHP 5 在类中找不到 __construct() 函数,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情况是:类中已有一个名为 __construct() 的方法,但它却又不是构造函数。
析构函数
void __destruct ( void )
PHP5引入了析构函数的概念,这类似于其它面向对象的语言,如C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
例子 19-7. 析构函数示例
<?php
class MyDestructableClass
{  function __construct()
   {    print "In constructor\n";
       $this->name = "MyDestructableClass";
   }
   function __destruct(){  print "Destroying".$this->name."\n";  }
}
$obj = new MyDestructableClass();
?>
和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。
注: 析构函数在脚本关闭时调用,此时所有的头信息已经发出。
注: 试图在析构函数中抛出一个异常会导致致命错误。
5.访问控制
对属性或方法的访问控制,是通过在前面添加关键字 public、protected 或 private 来实现的。由 public 所定义的类成员可以在任何地方被访问;由 protected 所定义的类成员则可以被其所在类的子类和父类访问(当然,该成员所在的类也可以访问);而由 private 定义的类成员则只能被其所在类访问。
对类成员的访问控制
类成员都必须使用关键字public、protected 或 private 进行定义
例 10.9. 声明类成员
<?php
/**  Define MyClass  */
class MyClass
{  public $public = 'Public';
   protected $protected = 'Protected';
   private $private = 'Private';
   function printHello()
   {   echo $this->public;
       echo $this->protected;
        echo $this->private;
   }
}
$obj = new MyClass();
echo $obj->public; // // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello();// Shows Public, Protected and Priv
class MyClass2 extends MyClass  //Define MyClass2
{// We can redeclare the public and protected method, but not private
    protected $protected = 'Protected2';
    function printHello()
   {   echo $this->public;
       echo $this->protected;
       echo $this->private;
   }
}
$obj2 = new MyClass2();
echo $obj->public; // Works
echo $obj2->private; // Undefined
echo $obj2->protected; // Fatal Error
$obj2->printHello();// Shows Public, Protected2, not Private
?>
注意:
在 PHP 4 中使用 var 关键字对变量进行定义的方法在 PHP 5 的面向对象语法中不再使用。为了顾及兼容性,在类中定义一个变量的话,该变量会被自动设为 public,并且产生一个 E_STRICT 警告。
对方法的访问控制
类中的方法都必须使用关键字public、protected 或 private 进行定义。如果没有设置这些关键字,则该方法会被设置成默认的 public。
例 10.10. 声明类中的方法
<?php
class MyClass   //Define MyClass
{   public function __construct() { }
    public function MyPublic() { }
    protected function MyProtected() { }
    private function MyPrivate() { }
    function Foo()
   {   $this->MyPublic();
       $this->MyProtected();
       $this->MyPrivate();
   }
}
$myclass = new MyClass;
$myclass->MyPublic(); //
$myclass->MyProtected(); //
$myclass->MyPrivate(); //
$myclass->Foo();
class MyClass2 extends MyClass    //Define MyClass2
{  // This is public
   function Foo2()
   {   $this->MyPublic();
       $this->MyProtected();
       $this->MyPrivate();
   }
}
$myclass2 = new MyClass2;
$myclass2->MyPublic();
$myclass2->Foo2();
?>
6.范围解析操作符(::)
范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员、方法和常量,还可以用于覆盖类中的成员和方法。当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。把 Paamayim Nekudotayim 选作该操作符的名字似乎有些奇怪。然而,这是Zend开发小组在写Zend Engine 0.5(被用于 PHP 3 中)时所作出的决定。事实上这个词在希伯莱文就是双冒号的意思。
例 10.11. 在类的外部使用 :: 操作符
<?php
class MyClass
{   const CONST_VALUE = 'A constant value';
}
echo MyClass::CONST_VALUE;
?>
self和parent这两个特殊的关键字是用于在类的内部对成员或方法进行访问的。
例 10.12. :: from inside the class definition
<?php
class OtherClass extends MyClass
{   public static $my_static = 'static var';
    public static function doubleColon()
    {   echo parent::CONST_VALUE . "\n";
       echo self::$my_static . "\n";
   }
}
OtherClass::doubleColon();?>
当一个子类覆盖其父类中的方法时,PHP不会再执行父类中已被覆盖的方法,直到子类中调用这些方法为止。这种机制也作用于构造函数和析构函数、重载及魔术函数。
例 10.13. 调用父类的方法
<?php
class MyClass
{    protected function myFunc() {    echo"MyClass::myFunc()\n";   }
}
class OtherClass extends MyClass
{  // Override parent's definition
   public function myFunc()
   {  // But still call the parent function
       parent::myFunc();
       echo "OtherClass::myFunc()\n";
   }
}
$class = new OtherClass();
$class->myFunc();
?>
7. 静态关键字(Static Keyword)
声明静态的类的成员和方法,使它不需要一个类的实例.一个static成员的声明不能通过一个类对象的实例来访问(尽管一个静态方法可以)。
静态声明必须在可见性声明之后。为了兼容PHP 4,如果没有可见性被声明,那么成员和方法将被当作是已经声明为public。
由于静态方法可以调用非对象实例,伪变量$this不可以在声明为静态的方法中使用。
事实上static方法调用形式在编译时被确定。当使用必须要声明的类名时,方法是完全标识和无继承规则的应用。当使用必须要声明的类名时,这种方法就被完全确认,而且没有使用继承的规则。
如果self已经被声明,那么self就被当前所属的类所解释。也不适用与继承规则。静态属性不能通过箭头操作符->.访问非静态方法,这将产生一个E_STRICT 级的警告。
例子 19-13. 静态成员的例子
<?php
class Foo
{   public static $my_static='foo';
    public function staticValue(){   return self::$my_static;   }
}
class Bar extends Foo
{   public function fooStatic(){   return parent::$my_static;   }
}
print Foo::$my_static."\n";
$foo = new Foo();
print $foo->staticValue()."\n";
print $foo->my_static."\n";// Undefined "Property" my_static
// $foo::my_static is not possible
print Bar::$my_static."\n";
$bar = new Bar();
print $bar->fooStatic()."\n";
?>
例子 19-14.静态方法实例(Static method example)
<?php
class Foo
{   public static function aStaticMethod() {    }
}
Foo::aStaticMethod();
?>
8. 类常量(Class Constants)
可以在每个基类中定义常量使它保持不变。在你不使用$符号去声明或使用它时,常量不同于普通变量。就象静态成员,常量值不能通过对象的实例来访问(而应使用$object::constant). 常量值必须是一个常量表达式,而不是一个变量,一个类的成员,一个数学表达式或函数调用的结果。
例子 19-15. 定义并使用一个常量
<?php
class MyClass
{   const constant = 'constant value';
    function showConstant() {   echo  self::constant."\n";   }
}
echo MyClass::constant."\n";
$class = new MyClass();
$class->showConstant();// echo $class::constant; is not allowed
?>
9. 抽象类(Class Abstraction)
PHP 5中引入了抽象类和抽象方法。不允许创建一个已经定义为abstract的类的一个实例。任何至少包含一个抽象方法的类也必须是抽象的。被定义为抽象的方法仅仅是声明方法的一个信号,并不能定义它们的实现。
当从一个抽象类继承时,在父类中所有抽象方法的标记的声明必须通过子类定义;另外,这些方法必须用定义相同的访问属性。例如,如果方法被定义为protected类型,执行函数必须定义为protected或public.
例子 19-16. 抽象类例子
<?php
abstract class AbstractClass
{   // Force Extending class to define this method
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);
    public function printOut()  // Common method
{    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
旧代码拥有非用户自定义的命名为abstract的类或函数将要运行如果没有被修改。
 10. 对象接口(Object Interfaces)
对象接口允许你创建一个指定类的方法的执行代码,而不必说明这些方法是如何被操作(处理)的。
接口被用来定义接口关键字的使用,同样作为一个标准类,但没有任何方法有它们内容的定义。
在接口中所有的方法必须声明为public,这是接口的特性。
implements (执行,实现)
为了实现一个接口,使用了implements操作。在接口中所有的方法必须在一个类的内部实现;疏忽这些将导致一个致命错误。如果渴望通过使用一个逗号分开每个接口,类可以实现多个接口。
例子 19-17. 接口实例
<?php
// Declare the interface 'iTemplate'
interface iTemplate
{   public function setVariable($name, $var);
    public function getHtml($template);
}
// Implement the interface . This will work
class Template implements iTemplate
{   private $vars = array();
    public function setVariable($name,$var){  $this->vars[$name]=$var;  }
    public function getHtml($template)
    {   foreach($this->vars as $name => $value)
         {   $template = str_replace('{'.$name.'}',$value,$template);
        }
         return $template;
    }
}
//This will not work Fatal error:Class BadTemplate contains 1 abstract
//methos and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{   private $vars = array();
    public function setVariable($name,$var){  $this->vars[$name] = $var;  }
}  ?>
11. 重载(Overloading)
方法调用和成员访问都能通过__call,__get和__set方法被加载。这些方法将只有当你试图访问不包括成员或方法的对象或继承对象时触发。不是所有的重载方法都必须被定义为static.
从PHP 5.1.0开始也可以通过__isset()和__unset()方法逐个重载isset()和unset()函数。
成员函数重载(Member overloading)
void __set ( string name, mixed value )
mixed __get ( string name )
bool __isset ( string name )
void __unset ( string name )
类成员可以通过定义这些指定的特定方法加载类中的自定义代码。$name参数被用来命名变量,这些变量必须是被设置的或返回的。__set()方法的$value参数指定设置$name的对象的值。
例子 19-18.使用__get,__set,__isset和__unset重载的例子
<?php
class Setter
{   public $n;
    private $x = array("a" => 1, "b" => 2, "c" => 3);
    private function __get($nm)
    {   echo "Getting [$nm]\n";
        if (isset($this->x[$nm]))
         {   $r = $this->x[$nm];
            print "Returning: $r\n";
            return $r;
        } else {   echo "Nothing!\n";   }
    }
    private function __set($nm, $val)
    {   echo "Setting [$nm] to $val\n";
        if (isset($this->x[$nm]))
         {   $this->x[$nm] = $val;
            echo "OK!\n";
        } else {    echo "Not OK!\n";   }
    }
    private function __isset($nm)
    {   echo "Checking if $nm is set\n";
         return isset($this->x[$nm]);
    }
    private function __unset($nm)
    {   echo "Unsetting $nm\n";
        unset($this->x[$nm]);
    }
}
$foo = new Setter();
$foo->n = 1;
$foo->a = 100;
$foo->a++;
$foo->z++;
var_dump(isset($foo->a)); //true
unset($foo->a);
var_dump(isset($foo->a)); //false
// this doesn't pass through the __isset() method
because 'n' is a public property
var_dump(isset($foo->n));
var_dump($foo);
?>
上例将输出:
Setting [a] to 100
OK!
Getting [a]
Returning: 100
Setting [a] to 101
OK!
Getting [z]
Nothing!
Setting [z] to 1
Not OK!
Checking if a is set
bool(true)
Unsetting a
Checking if a is set
bool(false)
bool(true)
object(Setter)#1 (2) {
  ["n"]=>int(1)["x:private"]=>array(2) {
["b"]=>
    int(2)
    ["c"]=>
    int(3)
  }
}
方法重载(Method overloading)
mixed __call ( string name, array arguments )
类方法可以通过定义这些指定的特定方法加载类中的自定义代码。$name参数被用来命名那些被请求的函数名。Arguments在定义为array的函数的$arguments参数中将被传递。从__call()方法返回的值将被返回方法的访问者。
例子 19-19.使用__call重载的实例
<?php
class Caller
{   private $x = array(1, 2, 3);
    public function __call($m, $a)
    {   print "Method $m called:\n";
        var_dump($a);
        return $this->x;
    }
}
$foo = new Caller();
$a = $foo->test(1, "2", 3.4, true);
var_dump($a);
?>
上例将输出:
Method test called:
array(4) {
    [0]=>
    int(1)
    [1]=>
    string(1) "2"
    [2]=>
    float(3.4)
    [3]=>
    bool(true)
}
array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
}
12.对象重叠(Object Iteration)
PHP5提供一个为对象定义通过一连串的消息被重述的途径成为可能,例如使用一个foreach语句。默认地,所有可见的属性将用来迭代(反复)。
例子 19-20. 简单的对象迭代(Simple Object Iteration)
<?php
class MyClass
{   public $var1 = 'value 1';
    public $var2 = 'value 2';
    public $var3 = 'value 3';
    protected $protected = 'protected var';
    private   $private   = 'private var';
    function iterateVisible()
    {   echo "MyClass::iterateVisible:\n";
       foreach($this as $key => $value){  print "$key => $value\n";  }
    }
}
$class = new MyClass();
foreach($class as $key => $value){   print "$key => $value\n";  }
echo "\n";
$class->iterateVisible();
?>
如输出显示,foreach重述能通过全部可见变量被访问。更进一步,你可以实现一个PHP5的指定的内在接口迭代器(Iterator)。允许对象描述什么是对象重述和对象如何被重述的。
例子 19-21. 迭代器实现对象迭代(Object Iteration implementing Iterator)
<?php
class MyIterator implements Iterator
{   private $var = array();
    public function __construct($array)
    {   if (is_array($array)){  $this->var = $array; }
    }
    public function rewind()
    {    echo "rewinding\n";
        reset($this->var);
    }
    public function current()
    {   $var = current($this->var);
        echo "current: $var\n";
        return $var;
    }
    public function key()
    {    $var = key($this->var);
        echo "key: $var\n";
        return $var;
    }
    public function next()
    {    $var = next($this->var);
        echo "next: $var\n";
        return $var;
    }
    public function valid()
    {    $var = $this->current() !== false;
        echo "valid: {$var}\n";
        return $var;
    }
}
$values = array(1,2,3);
$it = new MyIterator($values);
foreach ($it as $a => $b) {  print "$a: $b\n";  }
?>
上例将输出:
rewinding
current: 1
valid: 1
current: 1
key: 0
0: 1
next: 2
current: 2
valid: 1
current: 2
key: 1
1: 2
next: 3
current: 3
valid: 1
current: 3
key: 2
2: 3
next:
current:
valid:
在定义类时你也可以不必通过简单实现PHP5的IteratorAggregate接口定义所有的迭代器函数。
例19-22.IteratorAggregate对象迭代实现
<?php
class MyCollection implements IteratorAggregate
{   private $items = array();
    private $count = 0;
    // Required definition of interface IteratorAggregate
    public function getIterator()
    {    return new MyIterator($this->items);
    }
     public function add($value)
    {    $this->items[$this->count++] = $value;
    }
}
$coll = new MyCollection();
$coll->add('value 1');
$coll->add('value 2');
$coll->add('value 3');
foreach ($coll as $key => $val){  echo "key/value: [$key -> $val]\n\n";  }
?>
上例将输出:
rewinding
current: value 1
valid: 1
current: value 1
key: 0
key/value: [0 -> value 1]
next: value 2
current: value 2
valid: 1
current: value 2
key: 1
key/value: [1 -> value 2]
next: value 3
current: value 3
valid: 1
current: value 3
key: 2
key/value: [2 -> value 3]
next:
current:
valid:
13. 模式(Patterns)
模式是最好的实践和设计的描述方法。它给普通的编程问题展示一个可变的解决方案。
工厂模式(Factory)
工厂模式允许在运行的时间实例化一个对象。自从工厂模式命名以来,制造一个对象是可能的。
例子 19-23.工厂方法 (Factory Method)
<?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');  }
    }
}
?>
在类中允许定义一个驱动器在不工作时被加载的方法。如果类例子是一个数据库抽象类,可以象如下这样加载一个MySQL和SQLite驱动
<?php
 $mysql = Example::factory('MySQL'); // Load a MySQL Driver
 $sqlite = Example::factory('SQLite'); // Load a SQLite Driver
?>
单独模式(Singleton)
单模式适用于需要一个类的单独接口的情况。最普通的例子是数据库连接。这个模式的实现
允许程序员构造一个通过许多其他对象轻松地访问的单独接口。
例子 19-24.单模式函数(Singleton Function)
<?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
$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.
?>
 13. 魔法方法(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
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
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
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,…)形式的数组
14. 最终关键字(Final Keyword)
PHP5引入了最终关键字,防止子类使用final从一个重要的方法做定义的前缀。如果类本身已经被定义为final,类将不能被扩展。
例子 19-28.Final方法实例
<?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()
?>
例子 19-29. Final 类实例
<?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)
?> 
15.对象克隆(Object cloning)
通过完全地复制属性创建一个对象的拷贝不是通常想要的行为。需求的一个好的实例适合于拷贝构造函数,
如果有一个对象描述一个GTK窗口和对象保存这个GTK窗口的资源,当你创建一个副本,你或许想创建一个相同的属性新窗口使用和保存新对象资源的新窗口。另一个例子是当你复制父对象时如果保存一个引用给另一个对象,你想创建其他类的一个新实例来分开拷贝所属的复制品。一个对象的拷贝是使用clone关键字来创建的(如果可能的话可以调用对象的__clone()方法),一个对象的__clone()方法不能被直接声明。
 $copy_of_object = clone $object;
当一个对象被克隆时,PHP5将执行一个所有对象的属性的浅拷贝。任何对其它变量引用的属性将只保留引用。如果一个__clone()方法被定义,然后重新创建一个对象的克隆方法来允许任何必需的属性当它需要被改变时调用。
例子 19-30. 克隆一个对象
<?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
        )
)
16. 对象比较(Comparing objects)
在PHP5中,对象的比较比PHP4中的更复杂和更协调的期望的一个面向对象语言(倒不是说PHP5是这样的一门语言)。当使用比较操作符(==),对象变量以一种简单的方式被比较。也就是:如果它们具有相同的属性和值,两个对象的实例是相等,并且是同一个类的实例。
另一方面,当使用恒等式操作符(===)时,对象变量当且仅当它们引用同一个类的同一个实例时是相同的
一个例子就可以阐明这些规则
例子 19-31.PHP5中的对象比较实例
<?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
17. 映射(反射)Reflection 
介绍(Introduction)
PHP 5与一个API完全映射来以增加反向工程师类,接口,函数和方法的效率(性能)并加以扩展。另外, API映射并且为函数,类和方法提供获取文档注释的方法。
API映射是对Zend引擎一个面向对象的扩展。包括以下类:
<?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
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
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
/** 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
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
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
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()。
为了内省一个类,你必须首先创建ReflectionClass类的一个实例,你可以随后访问这个实例任何上述方法。
例子 19-35. 使用ReflectionClass 的类
<?php
interface Serializable  {    // ...}
class Object {    // ...}
/** A counter class */
class Counter extends Object implements Serializable
{   const START = 0;
    private static $c = Counter::START;
    /**Invoke counter
     * @access  public
     * @return  int */
    public function count() {  return self::$c++;  }
}
// Create an instance of the ReflectionClass class
$class = new ReflectionClass('Counter');
// Print out basic information
printf("===> The %s%s%s %s '%s' [extends %s]\n" .
    "     declared in %s\n" .
    "     lines %d to %d\n" .
    "     having the modifiers %d [%s]\n",
        $class->isInternal() ? 'internal' : 'user-defined',
        $class->isAbstract() ? ' abstract' : '',
        $class->isFinal() ? ' final' : '',
        $class->isInterface() ? 'interface' : 'class',
        $class->getName(),
        var_export($class->getParentClass(), 1),
        $class->getFileName(),
        $class->getStartLine(),
        $class->getEndline(),
        $class->getModifiers(),
        implode(' ', Reflection::getModifierNames($class->getModifiers()))
);
// Print documentation comment
printf("--->Documentation:\n %s\n",var_export($class->getDocComment(),1));
// Print which interfaces are implemented by this class
printf("--->Implements:\n %s\n",var_export($class->getInterfaces(),1));
// Print class constants
printf("--->Constants:%s\n",var_export($class->getConstants(),1));
// Print class properties
printf("--->Properties:%s\n",var_export($class->getProperties(),1));
// Print class methods
printf("--->Methods:%s\n",var_export($class->getMethods(),1));
// If this class is instantiable, create an instance
if ($class->isInstantiable())
{   $counter = $class->newInstance();
    echo '---> $counter is instance? ';
    echo $class->isInstance($counter) ? 'yes' : 'no';
    echo "\n---> new Object() is instance? ";
    echo $class->isInstance(new Object()) ? 'yes' : 'no';
}
?>
注:方法newInstance()通过象call_user_func()这样的函数接受自变量的一个变化的数值。
注:$class=new ReflectionClass('Foo');$class->isInstance($arg)等价于$arg instanceof Foo或is_a($arg, 'Foo').
映射方法(ReflectionMethod)
ReflectionMethod类允许你反向设计类方法。
<?php
class ReflectionMethod extends ReflectionFunction
{   public __construct(mixed class, string name)
    public string __toString()
    public static string export()
    public mixed invoke(stdclass object, mixed* args)
    public mixed invokeArgs(stdclass object, array args)
    public bool isFinal()
    public bool isAbstract()
    public bool isPublic()
    public bool isPrivate()
    public bool isProtected()
    public bool isStatic()
    public bool isConstructor()
    public bool isDestructor()
    public int getModifiers()
    public ReflectionClass getDeclaringClass()
    // Inherited from ReflectionFunction
    final private __clone()
    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 bool returnsReference()
    public ReflectionParameter[] getParameters()
    public int getNumberOfParameters()
    public int getNumberOfRequiredParameters()
}
?>
为了内省一个方法,你必须首先创建ReflectionMethod类的一个实例。你可以随后访问这个实例任何上述方法。
例子 19-36. Using the ReflectionMethod class
<?php
class Counter
{    private static $c = 0;
    /** Increment counter
     * @final
     * @static
     * @access  public
     * @return  int */    final public static function increment(){ return ++self::$c; }
}
// Create an instance of the Reflection_Method class
$method = new ReflectionMethod('Counter','increment');
// Print out basic information
printf( "===> The %s%s%s%s%s%s%s method '%s' (which is %s)\n" .
    "     declared in %s\n" .
    "     lines %d to %d\n" .
    "     having the modifiers %d[%s]\n",
        $method->isInternal() ? 'internal' : 'user-defined',
        $method->isAbstract() ? ' abstract' : '',
        $method->isFinal() ? ' final' : '',
        $method->isPublic() ? ' public' : '',
        $method->isPrivate() ? ' private' : '',
        $method->isProtected() ? ' protected' : '',
        $method->isStatic() ? ' static' : '',
        $method->getName(),
        $method->isConstructor() ? 'the constructor' : 'a regular method',
        $method->getFileName(),
        $method->getStartLine(),
        $method->getEndline(),
        $method->getModifiers(),
        implode(' ', Reflection::getModifierNames($method->getModifiers()))
);
// Print documentation comment
printf("--->Documentation:\n %s\n",var_export($method->getDocComment(),1));
if($statics=$method->getStaticVariables())//Print static variables if existant
 { printf("--->Static variables:%s\n",var_export($statics,1)); }
printf("--->Invokation results in: ");//Invoke the method
var_dump($method->invoke(NULL));
?>
注:试图调用私有的,保护的或抽象的方法将导致被invoke()方法抛出一个异常。静态方法如上所视,你必须通过NULL作为第一个自变量来invoke()。而非静态方法通过类的实例来调用。
映射属性(ReflectionProperty)
ReflectionProperty类允许你反向设计类属性。
<?php
class ReflectionProperty implements Reflector
{   final private __clone()
    public __construct(mixed class, string name)
    public string __toString()
    public static string export()
    public string getName()
    public bool isPublic()
    public bool isPrivate()
    public bool isProtected()
    public bool isStatic()
    public bool isDefault()
    public int getModifiers()
    public mixed getValue(stdclass object)
    public void setValue(stdclass object, mixed value)
    public ReflectionClass getDeclaringClass()
    public string getDocComment()
}
?>
注: 在PHP 5.1.0中增加了getDocComment()方法。
为了内省一个属性,你必须首先创建ReflectionProperty类的一个实例,你可以随后访问这个实例的任何上述方法。
例子 19-37. Using the ReflectionProperty class
<?php
class String
{   public $length  = 5;   }
// Create an instance of the ReflectionProperty class
$prop=new ReflectionProperty('String','length');
// Print out basic information
printf( "===> The%s%s%s%s property '%s' (which was %s)\n" .
    "   having the modifiers %s\n",
        $prop->isPublic() ? ' public' : '',
        $prop->isPrivate() ? ' private' : '',
        $prop->isProtected() ? ' protected' : '',
        $prop->isStatic() ? ' static' : '',
        $prop->getName(),
        $prop->isDefault() ? 'declared at compile-time' : 'created at run-time',
        var_export(Reflection::getModifierNames($prop->getModifiers()),1)
);
$obj= new String();//Create an instance of String
printf("--->Value is: ");//Get current value
var_dump($prop->getValue($obj));
$prop->setValue($obj,10); // Change value
printf("---> Setting value to 10, new value is: ");
var_dump($prop->getValue($obj));
var_dump($obj); //Dump object
?>
注:试图获得或设置私有的或保护的类属性的值将导致一个被抛出的异常。
 映射扩展(ReflectionExtension)
ReflectionExtension类允许你反向设计扩展。你可以在使用get_loaded_extensions()运行的时候重新返回所有加载的扩展。
<?php
class ReflectionExtension implements Reflector
{   final private __clone()
    public __construct(string name)
    public string __toString()
    public static string export()
    public string getName()
    public string getVersion()
    public ReflectionFunction[] getFunctions()
    public array getConstants()
    public array getINIEntries()
    public ReflectionClass[] getClasses()
    public array getClassNames()
}
?>
为了内省一个扩展,你必须首先创建ReflectionExtension类的一个实例。你可以随后访问这个实例的任何上述方法。
例子 19-38. 使用ReflectionExtension 的类
<?php
// Create an instance of the ReflectionProperty class
$ext=new ReflectionExtension('standard');
// Print out basic information
printf("Name        : %s\n" .
    "Version     : %s\n" .
    "Functions   : [%d] %s\n" .
    "Constants   : [%d] %s\n" .
    "INI entries : [%d] %s\n" .
    "Classes     : [%d] %s\n",
        $ext->getName(),
        $ext->getVersion()?$ext->getVersion():'NO_VERSION',
        sizeof($ext->getFunctions()),
        var_export($ext->getFunctions(),1),
        sizeof($ext->getConstants()),
        var_export($ext->getConstants(),1),
        sizeof($ext->getINIEntries()),
        var_export($ext->getINIEntries(),1),
        sizeof($ext->getClassNames()),
        var_export($ext->getClassNames(),1)
);
?>
扩展中的映射类(Extending the reflection classes)
万一你想创建一个构建类的专用的形式(就是说:在输出时创建彩色的HTML,拥有易访问的成员变量来代替方法或拥有公共方法),你可以继续和扩展它们。
例子 19-39. Extending the built-in classes
<?php
/**  My Reflection_Method class  */
class My_Reflection_Method extends ReflectionMethod
{   public $visibility = '';
    public function __construct($o, $m)
    {   parent::__construct($o, $m);
        $this->visibility= Reflection::getModifierNames($this->getModifiers());
    }
}
class T {  protected function x() { }  } //Demo class #1
class U extends T {  function x() { }  } //Demo class #2
var_dump(new My_Reflection_Method('U','x'));//Print out information
?>
注意警告:如果你重写构造函数,请记住在你插入任何代码之前通知父类的构造函数。不这样做将导致以下:致命错误: 内部错误:返回映射对象失败。
18. 类型提示(线索)Type Hinting
PHP5引入了类型提示。函数现在能给对象强制参数(在函数原型中通过指定类的名字)或数组(从PHP 5.1开始) 。
例子 19-40. Type Hinting examples
<?php
class MyClass // An example class
{/**A test function
    * First parameter must be an object of type OtherClass */
    public function test(OtherClass $otherclass) { echo $otherclass->var; }
    /*Another test function  * First parameter must be an array*/
    public function test_array(array $input_array){  print_r($input_array); }
}
class OtherClass{  public $var='Hello World';  }//Another example class
?> 
Failing to satisfy the type hint results in a fatal error.
<?php
// An instance of each class
$myclass = new MyClass;
$otherclass = new OtherClass;
// Fatal Error: Argument 1 must be an object of class OtherClass
$myclass->test('hello');
// Fatal Error: Argument 1 must be an instance of OtherClass
$foo = new stdClass;
$myclass->test($foo);
$myclass->test(null); //Fatal Error: Argument 1 must not be null
$myclass->test($otherclass); //Works: Prints Hello World
$myclass->test_array('a string');//Fatal Error:Argument 1 must be an array
$myclass->test_array(array('a', 'b', 'c'));//Works: Prints the array
?>
Type hinting also works with functions:
类型提示也可以与函数协同工作。
<?php
class MyClass {  public $var = 'Hello World';  }//An example class
/**A test function * First parameter must be an object of type MyClass  */
function MyFunction(MyClass $foo){  echo $foo->var;  }
$myclass = new MyClass; //Works
MyFunction($myclass);
?>
类型提示可以只是对象和数组(从PHP 5.1开始)类型。传统的类型提示不支持整型和字符串型。
第20章.异常处理
PHP5添加了类似于其它语言的异常处理模块,可以在 PHP内检测(try)、抛出(throw)和捕获(catch)异常。一个try至少要有一个与之对应的catch。定义多个catch可以捕获不同的对象。PHP会按这些catch被定义的顺序执行,直到完成最后一个为止。而在这些catch内,又可以抛出新的异常。
当一个异常被抛出时,其后(译者注:指抛出异常时所在的代码块)的代码将不会继续执行,而PHP就会尝试查找第一个能与之匹配的 catch。如果一个异常没有被捕获,而且又没用使用 set_exception_handler() 作相应的处理的话,那么PHP将会产生一个严重的错误,并且输出未能捕获异常的提示信息。
例子 20-1. 抛出一个异常
<?php
try
{   $error = 'Always throw this error';
    throw new Exception($error);
     //从这里开始,tra代码块内的代码将不会被执行
    echo 'Never executed';
}
catch(Exception $e){ echo 'Caught exception:',$e->getMessage(),"\n"; }
//继续执行
echo 'Hello World';
?>
扩展PHP内置的异常处理类
用户可以用自定义的异常处理类来扩展PHP内置的异常处理类。以下的代码说明了在内置的异常处理类中,哪些属性和方法在子类中是可访问和可继承的。译者注:以下这段代码只为说明内置异常处理类的结构,它并不是一段有实际意义的可用代码。
例子 20-2. 内置的异常处理类
<?php
class Exception
{   protected $message='Unknown exception';//异常信息
    protected $code = 0;        //用户自定义异常代码
    protected $file;           //发生异常的文件名
    protected $line;           //发生异常的代码行号
    function __construct($message = null, $code = 0);
    final function getMessage();     //返回异常信息
    final function getCode();       //返回异常代码
    final function getFile();       //返回发生异常的文件名
    final function getLine();       //返回发生异常的代码行号
    final function getTrace();      //backtrace()数组
    final function getTraceAsString();//已格成化成字符串的getTrace()信息
    /* 可重载的方法 */
    function __toString();          //可输出的字符串
}
?>
如果使用自定义的类来扩展内置异常处理类,并且要重新定义构造函数的话,建议同时调用 parent::__construct() 来检查所有的变量是否已被赋值。当对象要输出字符串的时候,可以重载 __toString() 并自定义输出的样式。
例子 20-3. 扩展PHP内置的异常处理类
<?php
/** 自定义一个异常处理类  */
class MyException extends Exception
{   //重定义构造器使message变为必须被指定的属性
    public function __construct($message, $code = 0)
    {   //自定义的代码,确保所有变量都被正确赋值
        parent::__construct($message, $code);
    }
    public function __toString() //自定义字符串输出的样式 */
    {   return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
    }
    public function customFunction()
    {   echo "A Custom function for this type of exception\n";
    }
}
/** 创建一个用于测试异常处理机制的类  */
class TestException
{   public $var;
    const THROW_NONE    = 0;
    const THROW_CUSTOM  = 1;
    const THROW_DEFAULT = 2;
    function __construct($avalue = self::THROW_NONE)
    {    switch ($avalue)
         {   case self::THROW_CUSTOM:
                throw new MyException('1 is an invalid parameter',5); //抛出自定义异常
                break;
            case self::THROW_DEFAULT:
                throw new Exception('2 isnt allowed as a parameter',6); //抛出默认的异常
                break;
            default:
                $this->var = $avalue; //没有异常的情况下,创建一个对象
                break;
        }
    }
}
// 例子 1
try
{ $o=new TestException(TestException::THROW_CUSTOM); }
catch(MyException $e)
{      //捕获异常
    echo "Caught my exception\n", $e;
    $e->customFunction();
}
catch(Exception $e){ echo"Caught Default Exception\n",$e;//被忽略 }
//执行后续代码
var_dump($o);
echo "\n\n";
// 例子 2
try
{  $o=new TestException(TestException::THROW_DEFAULT); }
catch(MyException $e){   //不能匹配异常的种类,被忽略
    echo "Caught my exception\n", $e;
    $e->customFunction();
}
catch(Exception $e){ echo"Caught Default Exception\n",$e;//捕获异常 }
// 执行后续代码
var_dump($o);
echo "\n\n";
// 例子 3
try {  $o=new TestException(TestException::THROW_CUSTOM); }
catch(Exception $e){ echo"Default Exception caught\n",$e; //捕获异常 }
//执行后续代码
var_dump($o);
echo "\n\n";
// 例子 4
try{ $o=new TestException(); }
catch(Exception $e){        //没有异常,被忽略
    echo "Default Exception caught\n", $e;
}
// 执行后续代码
var_dump($o);
echo "\n\n";
?>
Mambo相关站点:【上一篇】
关于Mambo (1):【下一篇】
【相关文章】
  • FC4上安装PHP5.1.2、Apache和Mysql等
  • apache2 php5 mysql5安装配置
  • 基于Flex+PHP+MySQL架构的Blog
  • PHP的伪重载
  • 一个开源的PHP OA groupoffice
  • php之call_user_func_array的简易用法
  • 用php生成静态html页面
  • 解决phpmyadmin中文乱码
  • PHP各种Template系统
  • 用php GD实现简单的透明度渐变的算法
  • 【随机文章】
  • eXtremeComponents导出时的中文文件名问题
  • IDS的规则建立(1)
  • VB.NET实现身份证15位升18位的算法
  • Mustang更名JDK6,JDK7项目启动
  • java学习笔记(只适用于初学者)
  • 7133 hotspare盘设置问题
  • 黑客惯用手法揭秘
  • 如何利用肉鸡上的Serv-U Ftp服务器
  • 实战部署基于 Linux 平台的 WEB 服务器(MySQL+Apache+GD+PHP+Zend+
  • Solaris 10 安装及SVC管理及X及Vmware及其它可能遇到的一些问题
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 软讯网络 All Rigths Reserved.