PHP V5.3新特性 第1部分: 对象接口的变化

IBM developerWorks 2008年12月10日 07:30 查看9762次 作者: John Mertic  【
文章分类:PHP5研究[新]
延迟静态绑定

在 V5.3 以前,PHP 存在的麻烦问题是如何处理静态方法和成员。到目前为止,使用自身或 __CLASS__ 进行的静态引用都是在定义函数的类作用域中解析的。问题在于,如果类进行了扩展并且调用来自新的子类,那么解析将是错误的。PHP V5.3 添加了延迟静态绑定来解决这个问题。为了更好地进行解释,我们在下面将创建一个具有静态方法的类。


清单 5. 使用静态方法 test()Foo
class Foo 
{
protected static $name = 'Foo';

public static function test()
{
return self::$name;
}
}

让我们对这个类进行扩展。我们将在子类中重新定义成员 $name


清单 6. 子类 Bar 扩展了父类 Foo
class Bar 
{
protected static $name = 'Bar';
}


我们在清单 7 中进行了静态调用。


清单 7. 静态方法调用 test()
echo Bar::test(); 

该调用的输出是字符串 Foo。这是因为在 test() 方法中进行的引用 self::$name 是在 Foo 类中完成的。这样绑定的原因是:函数是在 Foo 类中定义的。

PHP V5.3 添加了关键字 static 以允许针对当前类进行引用。因此将修改上面的 Foo 类以在清单 8 中使用该关键字,我们将看到输出的内容变成了 Bar


清单 8. 使用 static 关键字

class Foo 
{
protected static $name = 'Foo';

public static function test()
{
return static::$name;
}
}

class Bar
{
protected static $name = 'Bar';
}

echo Bar::test(); // outputs 'Bar'


有关 static 关键字需要注意一点,它的工作方式与在非静态上下文中的工作方式不同。这意味着普通的继承规则没有应用到静态调用中。静态关键字将仅仅尝试在当前类中解析调用,而不是在定义函数的类中执行。这一点值得注意。

现在您已经了解了有关静态方法和成员的增强,现在让我们看一看 PHP V5 中新添的类,它们构成了非常有用的部分:标准 PHP 库。


标准 PHP 库

标准 PHP 库(Standard PHP Library,SPL)是 PHP V5 中新增的接口和类的集合,旨在解决标准问题。这些问题包括实现可迭代的对象,使对象具有数组的行为或实现一个链接的列表。这些类和方法的优点是它们是原生 的 PHP,这意味用 PHP 本身实现它们会获得更快的速度。在很多情况下,这些类和方法还允许内部 PHP 函数直接使用这些对象,就像 Iterator 接口允许您使用 foreach 结构迭代对象一样。

PHP V5.3 向 SPL 添加了更多的类。我们前面提到一个类就是在 SPL 类 SplDoublyLinkedList 中实现的双重链接列表。它供其他两个新 SPL 类使用:SplStack(实现一个栈)和 SplQueue(实现一个队列)。

让我们看一看如何使用 SplStack 类实现一个栈。


清单 9. 使用 SplStack

$stack = new SplStack(); 

// push a few new items on the stack
$stack->push('a');
$stack->push('b');
$stack->push('c');

// see how many items are on the stack
echo count($stack); // returns 3

// iterate over the items in the stack
foreach ( $stack as $item )
echo "[$item],";
// the above outputs: [c],[b],[a]

// pop an item off the stack
echo $stack->pop(); // returns 'c'

// now see how many items are on the stack
echo count($stack); // returns 2

SqlQueue 也采取类似的方式,但是它像队列那样工作(先进先出;而不是像栈一样最后一个项进栈,第一个项出栈)。此外,还存在堆实现(SplHeap),以及针对某些情况的特定队列和堆实现(SplMinHeapSplMaxHeapSplPriorityQueue)。

另一个有用的补充是 SplFixedArray 类,顾名思义,这是一个固定大小的数组实现。然而,它的性能非常快 — 实际上它在基准测试中要比 PHP 内置数组实现快 10% 至 30%。造成这种速度优势的原因是数组是固定大小的,而默认的 PHP 数组是可变大小的,并且不允许非数值型索引。清单 10 显示了它的使用方法。


清单 10. SplFixedArray

$array = new SplFixedArray(3); 
$array[0] = 'dog';
$array[1] = 'cat';
$array[2] = 'bird';
$a->setSize(4); // increase the size on the fly
$array[3] = 'mouse';
foreach ( $array as $value )
echo "[$value],";

Output:
[dog],[cat],[bird],[mouse]


此外,添加了一些新的迭代器类:FilesystemIteratorGlobIterator。它们与 PHP 中的其他迭代器类使用相同的工作方式,但是它们分别针对不同的情况。

SPL 的另一个改变是现在的 PHP V5.3 通常启用 SPL。在以前的 PHP V5 版本中,可以在编译时禁用 SPL,但是 PHP V5.3 不能禁用 SPL。

SPL 中的新补充?? PHP 添加了一些有用的并且易于使用的功能,以及数据结构的实现,例如双重链接列表、栈、堆和队列。这些类可用于替换用户空间实现,这将改进速度并更好地集成各种 PHP 函数和构造。

现在我们已经了解了 SPL 中的一些新内容,让我们看一看 PHP V5.3 中的 OOP 如何通过循环垃圾收集获得显著的性能和内存使用改善。


循环垃圾收集

垃圾收集是 PHP 开发人员在性能方面遇到的一个问题。PHP 有一个非常简单的垃圾收集器,它实际上将对不再位于内存范围(scope)中的对象进行垃圾收集。垃圾收集的内部方式是使用一个引用计数器,因此当计数器 达到 0 时(意味着对该对象的引用都不可用),对象将被当作垃圾收集并从内存中删除。

这种方式工作得很好,但是如果一个对象使用父子关系引用另一个对象,那就会引发问题。在这种情况下,这些对象的引用计数器没有被收集,因此这些对象使用的内存仍然属于未引用的内存,并且直到完成请求后才能够进行分配。下面看一下关于这种问题的例子。

清单 11. PHP V5.2 及之前版本不能恰当地对父子类关系进行垃圾收集

class Parent 
{
public function __construct()
{
$this->child = new Child($this);
}
}

class Child
{
public function __construct(
Parent $parent
)
{
$this->parent = $parent;
}
}


在这种情况下,每当创建 Parent 类的实例并且该实例随后超出内存范围时,内存不会被释放,因此脚本在内存使用中不断增加。有一些用户空间解决方案可以解决这个问题。例如为父类创建一个解构函数将直接释放子对象。这种解构器必须在解除父类引用之前进行调用。但是执行这些工作会使您的代码也变得非常复杂。

在 PHP V5.3 中,垃圾收集器将检测这些循环引用,并且能够释放它们所占用的内存,因此在执行脚本时 PHP 内存使用情况将保持平稳。当 Parent 类的每个引用被删除后,Parent 类中的 Child 类引用也将会被当作垃圾收集。


结束语

PHP 在支持面向对象编程方面经历了长期的发展。PHP V4 时期的支持是比较弱的,但在 PHP V5 中得到显著的改善,并且后续版本还会调整。现在,PHP V5.3 提供了一些令人兴奋的改进,包括语法增强,例如新 __callStatic() 魔术方法、动态的静态调用、延迟静态绑定、静态方法和成员支持。它为 SPL 添加了新的内容,包括双重链接表、栈、堆和队列的实现,使您获得了一些常见的数据结构并且可以轻松使用它们。最后,期待已久的循环垃圾收集器是一个经过改 进的垃圾收集器,它恰当地为这些循环实例释放内存,解决了自引用类的内存和性能问题。所有这些特性使 PHP V5.3 成为一种更加强大的面向对象编程语言。





责任编辑:admin

给文章打分...

平均分:0.9(44 次)

-5 -4 -3 -2 -1 0 1 2 3 4 5
7

顶一下

发表我的见解...

  • 您的大名: 留空为匿名
  • 您的主页:
  • 您的邮箱: