PHP5新特性: 更加面向对象化的PHP

译者:yafeng
PHP 处理对象部分的内核完全重新开发过,提供更多功能的同时也提高了性能。在以前版本的 php 中,处理对象和处理基本类型(数字,字符串)的方式是一样的。这种方式的缺陷是:当将对象赋值给一个变量时,或者通过参数传递对象时,对象将被完全拷贝一份。在新的版本里,上述操作将传递引用(可以把引用理解成对象的标识符),而非值。
很多 PHP 程序员可能甚至没有察觉到老的对象处理方式。事实上,大多数的 php 应用都可以很好地运行。或者仅仅需要很少的改动。
私有和受保护成员
PHP5 引入了私有和受保护成员变量的概念。我们可以用它来定义类成员的可见性。
例子
受保护成员可以被子类访问, 而私有成员只能被类本身访问。
<?php
class MyClass {
   private $Hello = "Hello, World!/n";
   protected $Bar = "Hello, Foo!/n";
   protected $Foo = "Hello, Bar!/n";

   function printHello() {
       print "MyClass::printHello() " . $this->Hello;
       print "MyClass::printHello() " . $this->Bar;
       print "MyClass::printHello() " . $this->Foo;
   }
}

class MyClass2 extends MyClass {
   protected $Foo;
          
   function printHello() {
       MyClass::printHello();                          /* Should print */
       print "MyClass2::printHello() " . $this->Hello; /* Shouldn't print out anything */
       print "MyClass2::printHello() " . $this->Bar;  /* Shouldn't print (not declared)*/
       print "MyClass2::printHello() " . $this->Foo;  /* Should print */
   }
}

$obj = new MyClass();
print $obj->Hello;  /* Shouldn't print out anything */
print $obj->Bar;    /* Shouldn't print out anything */
print $obj->Foo;    /* Shouldn't print out anything */
$obj->printHello(); /* Should print */

$obj = new MyClass2();
print $obj->Hello;  /* Shouldn't print out anything */
print $obj->Bar;    /* Shouldn't print out anything */
print $obj->Foo;    /* Shouldn't print out anything */
$obj->printHello();
?>
私有方法和受保护方法
PHP5 也引入了私有方法和受保护方法的概念。
例子:
<?php
class Foo {
   private function aPrivateMethod() {
       echo "Foo::aPrivateMethod() called./n";
   }

   protected function aProtectedMethod() {
       echo "Foo::aProtectedMethod() called./n";
       $this->aPrivateMethod();
   }
}

class Bar extends Foo {
   public function aPublicMethod() {
       echo "Bar::aPublicMethod() called./n";
       $this->aProtectedMethod();
   }
}

$o = new Bar;
$o->aPublicMethod();
?>
以前的不使用类的老代码,没有访问修饰符( public, protected, private )的代码可以不经改动运行。
抽象类和抽象方法
Php5 也引入了抽象类和抽象方法的概念。抽象方法只是声明了方法的签名并不提供它的实现。包含抽象方法的类必须被声明成抽象类。
例子:
<?php
abstract class AbstractClass {
   abstract public function test();
}

class ImplementedClass extends AbstractClass {
   public function test() {
       echo "ImplementedClass::test() called./n";
   }
}

$o = new ImplementedClass;
$o->test();
?>
抽象类不能被实例化。以前的不使用抽象类的老代码可以不经改动运行。
接口
Php5 引入了接口。一个类可以实现多个接口。
例子:
<?php
interface Throwable {
   public function getMessage();
}

class MyException implements Throwable {
   public function getMessage() {
       // ...
   }
}
?>
以前的不使用接口的老代码可以不经改动运行
 
类的型别提示
PHP5 依然是弱类型的,不过在定义函数参数时,可以使用类的型别提示来声明期望传入的对象类型
Example
<?php
interface Foo {
   function a(Foo $foo);
}

interface Bar {
   function b(Bar $bar);
}

class FooBar implements Foo, Bar {
   function a(Foo $foo) {
       // ...
   }

   function b(Bar $bar) {
       // ...
   }
}

$a = new FooBar;
$b = new FooBar;

$a->a($b);
$a->b($b);
?>
和其他强类型语言一样, php5 类的型别提示在运行期间检查而非编译期间检查。即:
<?php
function foo(ClassName $object) {
   // ...
}
?>
和下面的代码是一样的:
<?php
function foo($object) {
   if (!($object instanceof ClassName)) {
       die("Argument 1 must be an instance of ClassName");
   }
}
?>
这个语法只适用于类,不适用于内建类型。
Final
 
PHP 5 引入了 final 关键字来声明 final 成员和 final 方法。 final 成员和 final 方法不能被子类覆盖。
Example
<?php
class Foo {
   final function bar() {
       // ...
   }
}
?>
更进一步,可以把类声明成 final 。将类声明成 final 可以阻止这个类被继承。 final 类里面的方法缺省地都是 final , 无需再声明一次。
Example
<?php
final class Foo {
   // class definition
}

// the next line is impossible
// class Bork extends Foo {}
?>
属性不能定义成为 final.
以前的不使用 final 的老代码可以不经改动运行 .
对象克隆
Php4 没有提供一种机制来让用户自己定义复制构造子( copy constructor )控制对象的复制过程。 Php4 做二进制的拷贝,因而很精确地复制了对象的所有属性。
精确地复制对象的所有属性可能并不是我们一直想要的。有个例子可以很好地说明我们确实需要复制构造子:比如一个 GTK Window 的对象 a a 持有它所需要的全部资源。当复制的这个 GTK Window 到对象 b 时候,我们更希望 b 持有新的资源对象。再举个例子:对象 a 包含了一个对象 c, 当你把对象 a 复制到对象 c 的时候。我们可能更希望对象 b 包含一个新的对象 c copy 而不是一个对象 c 的引用。(译者注:这里所说的就是浅克隆和深克隆。)
对象的复制是通过 clone 这个关键字达到的 (Clone 调用被克隆对象的 __clone() 方法 ) 。对象的 __clone 方法不能够直接被调用。
<?php
$copy_of_object = clone $object;
?>
developer创建对象的一份拷贝的时候,php5将会检查 __clone()方法是否存在。如果不存在,那么它就会呼叫缺省的__clone()方法,复制对象的所有属性。如果__clone()方法已经定义过,那么_clone()方法就会负责设置新对象的属性。为了方便起见,Engine会缺省地复制所有的属性。所以在__clone()方法中,只需要覆盖那些需要更改的属性就可以了。如下:
Example
<?php
class MyCloneable {
   static $id = 0;

   function MyCloneable() {
       $this->id = self::$id++;
   }

   function __clone() {
       $this->address = "New York";
       $this->id = self::$id++;
   }
}

$obj = new MyCloneable();

$obj->name = "Hello";
$obj->address = "Tel-Aviv";

print $obj->id . "/n";

$obj_cloned = clone $obj;

print $obj_cloned->id . "/n";
print $obj_cloned->name . "/n";
print $obj_cloned->address . "/n";
?>
统一构造函数
Php5 允许开发者声明一个类的构造方法。拥有构造方法的类在每次创建新的对象的时候都会呼叫这个方法,因此构造方法适合对象在被使用之前的初始化工作
Php4 中,构造方法的名称和类的名称一样。考虑到从子类构造方法呼叫父类构造方法的情况是非常普遍的,而将类从一个继承体系中搬迁引起的父类变更就常常导致需要更改类的构造方法, php4 的做法显然是不太合理的。
Php5 引入了一个声明构建函数的标准方法: __construct(). 如下:
Example
<?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();
?>
为保持向后的兼容性,如果 php5 不能够找到 __construct() ,它会寻找老式的构造方法,即与类同名的方法。简单的说,只有当老代码里包含了一个 __construct() 方法的时候,才存在一个兼容性的问题。
析构方法
对于面向对象的编程来说,可以定义 析构方法是非常有用的一个功能。析构方法可以用来记录调试信息,关闭数据库连接等等一些清除收尾的工作。 Php4 中没有析构方法,尽管 php4 已经支持可以注册一个函数以便请求结束的时候被调用。
Php5 引进的 析构方法的概念和其他面向对象的语言(比如 java )是一致的。当指向这个对象的最后一个引用被销毁的时候,析构方法被调用,调用完成后释放内存。注意:析构方法不接受任何参数。
Example
<?php
class MyDestructableClass {
   function __construct() {
       print "In constructor/n";
       $this->name = "MyDestructableClass";
   }

   function __destruct() {
       print "Destroying " . $this->name . "/n";
   }
}

$obj = new MyDestructableClass();
?>
和构建方法一样,父类的析构方法也不会被隐含调用。子类可以在自己的析构方法通过调用 parent::__destruct() 来显式地调用它。
Constants
Php5 引入了 class 级别的常量。
<?php
class Foo {
   const constant = "constant";
}

echo "Foo::constant = " . Foo::constant . "/n";
?>
老的没有使用 const 的代码仍然正常运行。
Exceptions
Php4 没有异常控制。 Php5 引入了和其它语言( java )相似的异常控制模式。应该注意的是 php5 里面支持捕捉全部异常,但是不支持 finally 子句。
catch 语句块里面,可以重新抛出异常。也可以有多个 catch 语句,在这种情况下,被捕捉到的异常从上往下依次比较和 catch 语句比较异常,第一个类型匹配的 catch 语句将会被执行。如果一直搜索到底还没有发现匹配的 catch 子句,则寻找下一个 try/catch 语句。最后不能捕捉的异常将被显示出来。如果异常被捕捉,那么程序会接着 catch 语句块的下面开始执行。
Example
<?php
class MyException {
   function __construct($exception) {
       $this->exception = $exception;
   }

   function Display() {
       print "MyException: $this->exception/n";
   }
}

class MyExceptionFoo extends MyException {
   function __construct($exception) {
       $this->exception = $exception;
   }

   function Display() {
       print "MyException: $this->exception/n";
   }
}

try {
   throw new MyExceptionFoo('Hello');
}
catch (MyException $exception) {
   $exception->Display();
}
catch (Exception $exception) {
   echo $exception;
}
?>
上面的例子表明可以定义一个并不继承自 Exception 的异常类,但是,最好还是从 Exception 继承并定义自己的异常。这是因为系统内建的 Exception 类能够收集到很多有用的信息, 而不继承它的异常类是得不到这些信息的。下面的 php 代码模仿了系统内建 Exception 类。每个属性后面都加了注释。每个属性都有一个 getter ,由于这些 getter 方法经常被系统内部处理调用,所以这些方法被标明了 final
Example
<?php
class Exception {
   function __construct(string $message=NULL, int code=0) {
       if (func_num_args()) {
           $this->message = $message;
       }
       $this->code = $code;
       $this->file = __FILE__; // of throw clause
       $this->line = __LINE__; // of throw clause
       $this->trace = debug_backtrace();
       $this->string = StringFormat($this);
   }

   protected $message = 'Unknown exception';  // exception message
   protected $code = 0; // user defined exception code
   protected $file;    // source filename of exception
   protected $line;    // source line of exception

   private $trace;      // backtrace of exception
   private $string;    // internal only!!

   final function getMessage() {
       return $this->message;
   }
   final function getCode() {
       return $this->code;
   }
   final function getFile() {
       return $this->file;
   }
   final function getTrace() {
       return $this->trace;
   }
   final function getTraceAsString() {
       return self::TraceFormat($this);
   }
   function _toString() {
       return $this->string;
   }
   static private function StringFormat(Exception $exception) {
       // ... a function not available in PHP scripts
       // that returns all relevant information as a string
   }
   static private function TraceFormat(Exception $exception) {
       // ... a function not available in PHP scripts
       // that returns the backtrace as a string
   }
}
?>
如果我们定义的一异常类都是继承自 Exception 基类
无兼容性问题。老的代码不会受到这一特性的影响。
Dereferencing objects returned from functions
Php4 中不能再次引用函数返回的对象以进一步呼叫返回对象的方法,而 php5 是可以的。
<?php
class Circle {
   function draw() {
       print "Circle/n";
   }
}
      
class Square {
   function draw() {
       print "Square/n";
   }
}

function ShapeFactoryMethod($shape) {
   switch ($shape) {
       case "Circle":
           return new Circle();
       case "Square":
           return new Square();
   }
}

ShapeFactoryMethod("Circle")->draw();
ShapeFactoryMethod("Square")->draw();
?>
静态成员变量能够被初始化。
Example
<?php
class foo {
   static $my_static = 5;
   public $my_prop = 'bla';
}

print foo::$my_static;
$obj = new foo;
print $obj->my_prop;
?>
静态方法
PHP 5 引入了静态方法,可以在不实例化类的情况下呼叫静态方法。
Example
<?php
class Foo {
   public static function aStaticMethod() {
       // ...
   }
}

Foo::aStaticMethod();
?>
伪变量 $this 不能够在静态方法方法中使用。
instanceof
Php5 引入了 instanceof 关键字,允许用它来测试一个对象是一个类的实例,或者是一个派生类的实例,或者实现了某个接口
Example
<?php
class baseClass { }

$a = new baseClass;

if ($a instanceof baseClass) {
   echo "Hello World";
}
?>
Static function variables
现在,静态变量在编译阶段处理。因此程序员可以通过引用为静态变量赋值。这可以改善性能,不过,不能够使用对静态变量的间接引用了。
按引用传递的函数参数现在也可以设置缺省值了。
Example
<?php
function my_function(&$var = null) {
   if ($var === null) {
       die("$var needs to have a value");
   }
}
?>
__autoload()
__autoload() 拦截函数在一个未声明的类被初始化的时候自动调用。该类的名字会被自动传递给 __autoload() 函数。而 __autoload() 也只有这么唯一的一个参数。
Example
<?php
function __autoload($className) {
   include_once $className . ".php";
}

$object = new ClassName;
?>
可重载的方法呼叫和属性访问
方法呼叫和属性访问都能够通过 __call, __get() and __set() 方法重载。
Example: __get() and __set()
<?php
class Setter {
   public $n;
   public $x = array("a" => 1, "b" => 2, "c" => 3);

   function __get($nm) {
       print "Getting [$nm]/n";

       if (isset($this->x[$nm])) {
           $r = $this->x[$nm];
           print "Returning: $r/n";
           return $r;
       } else {
           print "Nothing!/n";
       }
   }

   function __set($nm, $val) {
       print "Setting [$nm] to $val/n";

       if (isset($this->x[$nm])) {
           $this->x[$nm] = $val;
           print "OK!/n";
       } else {
           print "Not OK!/n";
       }
   }
}

$foo = new Setter();
$foo->n = 1;
$foo->a = 100;
$foo->a++;
$foo->z++;
var_dump($foo);
?>
Example: __call()
<?php
class Caller {
   private $x = array(1, 2, 3);

   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);
?>
迭代
当和 foreach 一起使用对象的时候,迭代的方式被重载过了。缺省的行为是迭代类的所有属性。
Example
<?php
class Foo {
   public $x = 1;
   public $y = 2;
}

$obj = new Foo;

foreach ($obj as $prp_name => $prop_value) {
   // using the property
}
?>
一个类的所有对象都能够被迭代浏览到, 如果这个类实现了一个空的接口: Traversable. 换句话说,实现了 Traversable 接口的类可以和 foreach 一起使用。
接口 IteratorAggregate Iterator 允许指定类的对象在代码中如何迭代。 IteratorAggregate 接口有一个方法: getIterator() 必须返回一个数组
Example
<?php
class ObjectIterator implements Iterator {

   private $obj;
   private $num;

   function __construct($obj) {
       $this->obj = $obj;
   }
   function rewind() {
       $this->num = 0;
   }
   function valid() {
       return $this->num < $this->obj->max;
   }
   function key() {
       return $this->num;
   }
   function current() {
       switch($this->num) {
           case 0: return "1st";
           case 1: return "2nd";
           case 2: return "3rd";
           default: return $this->num."th";
       }
   }
   function next() {
       $this->num++;
   }
}

class Object implements IteratorAggregate {

   public $max = 3;

   function getIterator() {
       return new ObjectIterator($this);
   }
}

$obj = new Object;

// this foreach ...
foreach($obj as $key => $val) {
   echo "$key = $val/n";
}

// matches the following 7 lines with the for directive.
$it = $obj->getIterator();
for($it->rewind(); $it->hasMore(); $it->next) {
   $key = $it->current();
   $val = $it->key();
   echo "$key = $val/n";
}
unset($it);
?>
新的__toString方法
可以通过覆盖 __toString 方法来控制对象到字符串的转换。
Example
<?php
class Foo {
   function __toString() {
       return "What ever";
   }
}

$obj = new Foo;

echo $obj; // call __toString()
?>
Reflection API
Php5 引入了全套的反射 API ,以支持对类,接口,函数,方法的反向工程。
它也提供了 API 以从程序中提取注释文档。反射 API 的详细资料参考此处: http://sitten-polizei.de/php/reflection_api/docs/language.reflection.html
Example
<?php
class Foo {
   public $prop;
   function Func($name) {
       echo "Hello $name";
   }
}

reflection_class::export('Foo');
reflection_object::export(new Foo);
reflection_method::export('Foo', 'func');
reflection_property::export('Foo', 'prop');
reflection_extension::export('standard');
?>
新内存管理机制
Php5 有一个全新的内存管理机制,使得它在多线程的环境下可以更有效地运行。在分配和释放内存时,不再使用 mutex 锁定 / 解除锁定
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值