1、首先对之前滥用的语法进行了规范
众所周知PHP在语言开发过程中有一个很好的容错性,导致在数组或全局变量中包含字符串不使用引号是可以不报错的,很多业余的开发者因为懒惰而产生的安全问题十分严重,之所以PHP5.3对所有基本的语法进行了重新整理和提高写作规范,其实对PHP开发者来讲写作上并没有太大的影响,只是让他们变的更加专业。
2、MySQL驱动Mysqli 提高效率
一直以来,php都是通过mysql客户端连接mysql,而现在mysql官方已经推出php版的mysql客户端,而这个mysqlind有效降低内存的使用以及提高性能。mysqlnd进入核心扩展,理论上说该扩展访问mysql速度会较之前的MySQL 和 MySQLi 扩展快(参见http://dev.mysql.com/downloads/connector/php-mysqlnd/)
(1)编译php更方便了,不需要libmysql,已经内置在源码中
(2)使用php许可,避免版权问题
(3)使用php的内存管理,支持php内存限制(memory_limit)
(4)所有数据在内存只有一份,之前的libmysql有两份
(5)提供性能统计功能,帮助分析瓶颈
(6)在驱动层增加缓存机制
3、PHP5.3安全和性能的提升
如md5()大概提高了10%-15%的性能,更好的内存处理机制,提高软件性能的访问。解决了include(require)_once重复打开的问题,之前once都是用静态变量实现的,用gcc4编译的二进制文件将更小,整体性能提高了5%-15%
4、延迟静态绑定
PHP的静态是在预编译时就固定好的,所以在继承的时候,父类里的self指的是父类,而不是子类。而php5.3加入了新的语法static,可以在运行时候捕捉当前类。
在PHP5中,我们可以在类中通过self关键字或者__CLASS__来判断或调用当前类。但有一个问题,如果我们是在子类中调用,得到的结果将是父类。因为在继承父类的时候,静态成员就已经被绑定了。 例如:
<?php class A { public static function who() { echo __CLASS__; } public static function test() { self::who(); } } class B extends A { public static function who() { echo __CLASS__; } } B::test(); //以上代码会输出A ?>
这和我们的预期不同,我们原来想得到子类的相应结果。PHP 5.3.0中增加了一个static关键字来引用当前类,即实现了延迟静态绑定:
<?php class A { public static function who() { echo __CLASS__; } public static function test() { static::who(); // 这里实现了延迟的静态绑定 } } class B extends A { public static function who() { echo __CLASS__; } } B::test(); //以上代码会输出B ?>
5、更多新特性
(1)名字空间,用来解决命名被污染
毫无疑问,命名空间是PHP5.3所带来的最重要的新特性。有了命名空间的概念,在开发大型站点时,就比较容易设计出灵活的结构,同时避免不同包中的类名或变量名产生冲突。
<?php namespace Zend/Db/Table; class Select {} ?>
这样即使其它命名空间下存在名为Select的类,程序在调用时也不会产生冲突。代码的可读性也有所增加。
(2)新的魔法函数 __callStatic 原来 __call的静态模式
PHP中原本有一个魔术方法__call(),当代码调用对象的某个不存在的方法时该魔术方法会被自动调用。新增的__callStatic()方法则只用于静态类方法。当尝试调用类中不存在的静态方法时,__callStatic()魔术方法将被自动调用。
<?php class MethodTest { public function __call($name, $arguments) { // 参数 $name 大小写敏感 echo "调用对象方法 '$name' " . implode(' -- ', $arguments). "/n"; } /** PHP 5.3.0 以上版本中本类方法有效 */ public static function __callStatic($name, $arguments) { // 参数 $name 大小写敏感 echo "调用静态方法 '$name' " . implode(' -- ', $arguments). "/n"; } } $obj = new MethodTest; $obj->runTest('通过对象调用'); MethodTest::runTest('静态调用'); // As of PHP 5.3.0 //以上代码执行后输出如下: //调用对象方法'runTest' –- 通过对象调用 //调用静态方法'runTest' –- 静态调用 ?>
(3)动态的静态调用。PHP中有一个实用的特性是变量的变量。它意味着你可以用一个变量的字符串值作为另外一个变量的名字。换句话说,你可以完成下面的功能。
x = 'y'; $$x = 'z'; echo $x; // 输出'y' echo $$x; // 输出'z'
同样的概念可以用于函数,甚至类的成员函数。如下例所示:
class Dog { public function bark() { echo "Woof!"; } } $class = 'Dog' $action = 'bark'; $x = new $class(); // 实例化类'Dog' $x->$action(); // 输出"Woof!"
在PHP V5.3中增加了一个功能,静态调用中的类名可以通过一个变量来指定。由此引入了一些新的编程方法,如下所示下面的例子就是通过$someClass::$method()调用
<?php class Test { public static function testgo() { echo "gogo!"; } } $class = 'Test'; $action = 'testgo'; $class::$action(); //输出 "gogo!" ?>
这个新增功能使得PHP中变量的变量这个特性成为一个完备特性,可用于各种环境。
(4)新增日期函数date_create_from_format,别名 DateTime::createFromFormat()。
<?php $date = date_create_from_format('j-M-Y', '28-Feb-2014'); echo $date->format('Y-m-d'); //输出 2014-02-28 ?>
(5)新魔法常量 __DIR__ 来解决路径问题
在5.3以前,为了获得当前脚本的目录,需要一次函数调用
echo dirname(__FILE__); // < PHP 5.3
在5.3,只需要一个魔术常量__DIR__就解决了
echo __DIR__; // >= PHP 5.3
(6)goto语句
多数计算机程序设计语言中都支持无条件转向语句goto,当程序执行到goto语句时,即转向由goto语句中的标号指出的程序位置继续执行。尽管goto语句有可能会导致程序流程不清晰,可读性减弱,但在某些情况下具有其独特的方便之处,例如中断深度嵌套的循环和 if
语句。
<?php goto a; echo 'Foo'; a: echo 'Bar'; for($i=0,$j=50; $i<100; $i++) { while($j--) { if($j==17) goto end; } } echo "i = $i"; end: echo 'j hit 17'; ?>
(7)新增了类似JavaScript中的匿名函数和闭包。闭包(Closure)函数和Lambda函数的概念来自于函数编程领域。例如JavaScript 是支持闭包和lambda 函数的最常见语言之一。
在PHP中,我们也可以通过create_function()
在代码运行时创建函数。但有一个问题:创建的函数仅在运行时才被编译,而不与其它代码同时被编译成执行码,因此我们无法使用类似APC这样的执行码缓存来提高代码执行效率。
在PHP5.3中,我们可以使用Lambda/匿名函数来定义一些临时使用(即用即弃型)的函数,以作为array_map()/array_walk()
等函数的回调函数。
例 对象内的闭包
<?php echo preg_replace_callback('~-([a-z])~', function ($match) { return strtoupper($match[1]); }, 'hello-world'); // 输出 helloWorld $greet = function($name) { printf("Hello %s/r/n", $name); }; $greet('World'); $greet('PHP'); //...在某个类中 $callback = function ($quantity, $product) use ($tax, &$total) { $pricePerItem = constant(__CLASS__ . "::PRICE_" . strtoupper($product)); $total += ($pricePerItem * $quantity) * ($tax + 1.0); }; array_walk($products, $callback); ?>
闭包与对象
闭包不但是过程式编程的有用工具,而且是面向对象编程的有用工具。在这种情况下使用闭包与在类外部使用闭包实现的目的相同:包含在小范围内绑定的特定函数。在对象外部与在对象内部使用一样简单。
在对象内定义时,非常方便的一点是闭包通过 $this
变量拥有对对象的完全访问权,而无需显式导入。下面代码演示了该示例。
例 静态闭包
<?php class Dog { private $_name; protected $_color; public function __construct($name, $color) { $this->_name = $name; $this->_color = $color; } public function greet($greeting) { return function() use ($greeting) { echo "$greeting, I am a {$this->_color} dog named {$this->_name}."; }; } } $dog = new Dog("Rover","red"); $current = $dog->greet("Hello");//因为返回的是一个闭包,所以需要先将返回的闭包函数赋予一个变量, //然后再在下一行输出该变量,并带括号.如果直接输出,将返回错误 //Object of class Closure could not be converted to string $current(); //Output: //Hello, I am a red dog named Rover. ?>
在这里,我们在闭包内显式使用提供给 greet()
方法的欢迎词,闭包在该方法内定义。我们还在闭包内获取狗的颜色和名字,传递到构造函数中并存储到对象中。
在类中定义的闭包基本上与在对象外部定义的闭包相同。惟一的不同之处在于通过 $this
变量自动导入对象。我们可以通过将闭包定义为静态闭包禁用此行为。
<?php class House { public function paint($color) { return static function() use ($color) { echo "Painting the house $color...."; }; } } $house = new House(); $current = $house->paint('red'); $current(); //Output: //Painting the house red.... ?>
该闭包被定义为静态类,所以闭包内不能使用对象的任何属性。
在对象内使用静态闭包与使用非静态闭包相比的最大优点是节省内存。由于无需将对象导入闭包中,因此可以节省大量内存,尤其是在拥有许多不需要此功能的闭包时。
针对对象的另一个优点是添加名为 __invoke()
的魔术方法,此方法允许对象本身被调用为闭包。如果定义了此方法,则在该上下文中调用对象时将使用此方法。下例演示了示例。
例 使用 __invoke()
方法
class Dog { public function __invoke() { echo "I am a dog!"; } } $dog = new Dog(); $dog();
将上例中所示的对象引用调用为变量将自动调用 __invoke()
魔术方法,使类本身用作闭包。
闭包可以很好地与面向对象的代码以及面向过程的代码整合。让我们看一看闭包如何与 PHP 的强大 Reflection API 交互。
闭包与反射
PHP 有一个有用的反射 API,它允许我们对类、接口、函数和方法执行反向工程。按照设计,闭包是匿名函数,这意味着它们不显示在反射 API 中。
但是,新 getClosure()
方法已经添加到 PHP 中的 ReflectionMethod
和 ReflectionFunction
类中,可以从指定的函数或方法动态创建闭包。它在此上下文中用作宏,通过闭包调用函数方法将在定义它的上下文中执行函数调用。下例显示了此方法如何运行。
例 使用 getClosure()
方法
<?php class Counter { private $x; public function __construct() { $this->x = 0; } public function increment() { $this->x++; } public function currentValue() { echo $this->x . " "; } } $test = new Counter(); $class = new ReflectionClass('Counter'); $method = $class->getMethod('currentValue'); $closure = $method->getClosure($test); $closure(); //$class->increment(); $method2 = $class->getMethod('increment'); $closure2 = $method2->getClosure($test); $closure2(); $closure(); //Output: //0 //1 ?>
这种方法的一个有趣的副作用是允许通过闭包访问类的私有成员和受保护成员,这有利于对类执行单元测试。下例展示了对类的私有方法的访问。
<?php class Example { //.... private static function secret() { echo "I'm an method that's hiding!"; } //... } $class = new ReflectionClass('Example'); $method = $class->getMethod('secret'); $closure = $method->getClosure(new Example()); $closure(); //Output: //I'm an method that's hiding! ?>
(8)新的垃圾收集器(GC),并默认启用.
PHP开发者经常碰到的一个性能瓶颈是垃圾回收。PHP有一个非常简单的垃圾回收器,用于回收不在作用域内的对象。它的原理是通过引用计数,当计数到达0时(意味着不再有引用指向该对象),该对象被回收,释放占用的内存。PHP V5.3通过采用循环垃圾回收技术来提高OOP的性能与内存消耗。
这种方式简单高效,但是在父子关系的对象引用中会产生问题。此时,这些对象的引用计数器不为0,所以不会被回收,一直存在到请求的结束。下面我们来看这个问题的一个例子。
<?php class Parent { public function __construct() { $this->child = new Child($this); } } class Child { public function __construct( Parent $parent ) { $this->parent = $parent; } } for ($i = 0; $i < 1000; $i++) { new Parent(); } ?>
在这个例子中,你每次创建一个Parent对象,然后该对象不再被引用,但是内存不会被释放,所以脚本的内存消耗持续增加。在用户空间,存在一些方法来解决该问题,比如为Parent类提供一个析构函数,直接释放引用的子对象。但是你必须在释放Parent对象前显式调用该析构函数,如果一直这么做,将使你的代码变得非常复杂。
在PHP V5.3中,垃圾回收器将会检测这种循环引用并释放它们,从而使该脚本的内存使用保持在正常状态。当Parent对象的引用计数为0时,Parent内部引用的Child对象也将被回收。
(9)、标准PHP库
PHP V5中新增的标准PHP库是用于解决标准问题的一组类和接口。这些问题包括可迭代对象、数组对象和链表等。使用这些类和接口的好处是:它们是PHP的原生 方法,比用PHP实现的效率要高。 同时,它们使得许多PHP内置函数和语言结构可以直接使用这些对象,比如你可以通过foreach结构遍历一个实现了迭代器接口的对象。
PHP V5.3在SPL中增加了若干个类。如早前提到过的双向链表SplDoublyLinkedList。SPL中新增的栈和队列类:SplStack和SplQueue的实现中都使用了该类。
下面看一下如何使用SplStack类实现一个栈。
<?php $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 ?>
SplQueue类与SplStack相似,实现了队列功能(先进先出,而栈是先进后出)。此外,还实现了堆(SplHeap)以及一些特殊的队列和堆实现,如(SplMinHeap、SplMaxHeap和SplPriorityQueue)。
另外新增的一个实用类是SplFixedArray,如名字暗示的那样,它是一个固定大小的数组实现。不过,它的速度比PHP内置的数组要快20-30%,原因是它是固定大小的,而内置数组是变长的,并且它只允许数字索引。下面演示了它的用法。
<?php $array = new SplFixedArray(3); $array[0] = 'dog'; $array[1] = 'cat'; $array[2] = 'bird'; $array->setSize(4); // increase the size on the fly $array[3] = 'mouse'; foreach ( $array as $value ) echo "[$value],"; //Output: [dog],[cat],[bird],[mouse], ?>
此外,还增加了两个迭代器类:FilesystemIterator和GlobIterator。它们的行为与PHP中的其它迭代器一致,只不过它们是为特定目的而定制的。
另外一个变化是SPL在PHP V5.3中将强制启用。以前的PHP V5版本,你可以在编译的时候禁止SPL,但是这个选项现在没有了。
SPL的改善提高了PHP的易用性,并实现了数据结构如双向链表、栈、堆和队列等。它们可以替换用户自己实现的这些数据结构,这样不但可以提高效率,而且还可以促进PHP函数和语言结构的整合。
(10)NOWDOC
php定义字符串有一种格式叫定界符.
$foo = <<<ONE this is $fubar ONE;
这种方式称为HEREDOC,php会解析里面的变量,而有时候我们不需要解析变量,5.3加入了NOWDOC,其实就是定界符的单引号版。
$bar = <<<'TWO' this is $fubar TWO;
这样,php只把它当作字符串,变量不会解析
完成。