`
kokko
  • 浏览: 12673 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

PHP 5.3 新特性总结

阅读更多
一、前言
早在PHP5的发布在面向对象编程(OOP)和设计方面迈出了很大的进步,它提供了很多新特性,例如类的可见性、类反射等。可以说它为PHP面向对象编程做出了不可磨灭的贡献。PHP V5.3在OOP方面提供了大量的补充,它的发布旨在为开发人员在未来使用 PHP V6 做准备,被誉为 “只缺少原生 Unicode 支持的 PHP V6”,它增加了一些新的特性,删除了一些在未来PHP版本中不会再出现的特性,在做coolPHP的开发中,笔者根据实际使用总结了一些PHP5.3的新特性,这只是茶余饭后的一篇总结罢了...

二、新特性
1、新的魔术方法__callStatic()
了解这个方法之前,有必要了解一下静态方法和成员变量以及PHP5中魔术方法。早在PHP V4中就支持对方法和类成员的静态访问,但是它不能够将方法或者成员指定为专门用于静态访问的属性,比如在PHP V4中
<?php
class Test {
   var $name;

   function Test(){
	$this->name = 'kokko';
   }

   function static1() {
       return '1';
   }

   function static2() {
       // 在PHP5中我们使用self::static1()方式调用动态方法
       return Test::static1() . ' and 2';
   }
}

//现在我们使用static的方式调用方法,将返回‘1 and 2’
echo Test::static2();
?> 

我们可以使用静态的方式调用Test::static2(),而不需要声明addItem为静态访问,而在PHP V5中我们能够将方法和成员变量声明为静态的,我们可以将上述代码改为
<?php
class Test {
   static $name = 'kokko';

   static function static1() {
       return '1';
   }
   static function static2() {
       // 在PHP5中我们使用self::static1()方式调用动态方法
       return self::static1() . ' and 2';
   }
}

//现在我们使用static的方式调用方法,将返回‘1 and 2’
echo Test::static2();
?> 

PHP5中不仅仅提供了对静态变量的定义,还提供了许多Magic Methods(魔术方法),魔术方法的引入提供了(比如__call)重载方法的支持(JAVA开发者很熟悉这个概念,就是一个方法允许多个不同的类型的参数)和多态的支持,极大的丰富了OOP编程方法,使得PHP也可以利用各种设计模式Coding(记得很早就有人曾经问过我Head First设计模式本书中的鸭子能在PHP中实现吗?)。在PHP V5.3中添加了一种姓的魔术方法:__callStatic(),他的工作方式与__call()魔术方法没有太大的区别,__call()它专门用来处理那些没有在类中定义的或者对类不可见的方法的调用而生的,而__callStatic是用来处理静态方法的调用,它可以提供更好的方法重载方式。比如:
class Test{
	public static function __callStatic( $name,$args ){
		return "静态调用{$name}方法!";
	}

	public function __call($name,$args){
		return "调用{$name}方法";
	}
}

echo Test::getItem(1);	//输出‘静态调用getItem方法!’
$test = new Test();
$test->getItem(1);	//输出‘调用getItem方法!’


2、动态的调用静态方法和成员变量
<?php
class Test 
{ 
    public static $name = 'kokko';

	public static function doTest() 
    { 
         return 'testing...';
    } 
} 

$class = 'Test'; 
$action = 'doTest'; 
$name = '$name';

//输出 "testing..." 
echo Test::$action();  
//输出  'kokko'
echo Test::$name;  
//输出 "Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM, expecting ',' or ';' in E:\eusite\php3\test.php on line 13" 
echo $class::$action();
//输出 "Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM, expecting ',' or ';' in E:\eusite\php3\test.php on line 20" 
echo $class::$name;  
?> 

在PHP以往的版本中是不可以通过可变变量(可以使用某个变量的字符串值指定另一个变量的名称)的方式调用静态方法的,PHP V5.3中添加了动态的调用静态方法的特性,我们现在可以使用$class::$action()的方式调用静态方法了。

3、赋予static关键字新的特性实现延迟静态绑定
<?php
class Test 
{ 
    public static $name = 'kokko';

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

class Test2 extends Test{
	public static $name = 'kokko won';
}

//输出kokko
echo Test2::doTest();
?> 

上述代码我本来实现输出'kokko won',但是实际上事与愿违,doTest方法中调用的self::$name由于是在Test类中完成的,所以输出的是'kokko',我们要想达到目的只有在子类中覆盖doTest静态方法,在PHP V5.3 中赋予了关键字static的新特性,允许针对当前类进行引用:
<?php
class Test 
{ 
    public static $name = 'kokko';

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

class Test2 extends Test{
	public static $name = 'kokko won';
}

//输出kokko won
echo Test2::doTest();
?> 


4、新的SPL数据结构类和迭代器类
标准 PHP 库(Standard PHP Library,SPL)是 PHP V5 中新增的接口和类的集合,PHP V5.3继续进行扩展,增加了更多的类,比如SplDoublyLinkedList类以提供双重链接列表支持;SplStack实现堆支持;SplQueue实现队列支持;SplFixedArray实现一个固定大小的数组(PHP中默认的数组是可变大小的),该数据结构是固定大小的,而且不允许非数值型索引(NO $arr['kokko']),它的性能也是非常的快,据说比标准的内置数组快10%至30%,笔者测试了一下,将一个1000元素的数组比较是快20%左右(结果更机器还是有关系的,笔者的本本刚买不久)!另外标准库中还新增了FilesystemIterator和GlobIterator等迭代器类。更重要的一点是在PHP V5.3中不能禁用对SPL的支持,大家应该可以看出点什么来!
<?php
$stack = new SplStack(); 
$stack->push('kokko'); 
$stack->push('won'); 

//count 可以获取堆中元素数目
echo count($stack); // 输出2

//循环输出元素
foreach ( $stack as $item ) {
	echo $item."\n";
}

// 出栈,输出won
echo $stack->pop();

//计算当期堆中元素数
echo count($stack); // 输出 1
?>


5、垃圾回收及自动内存释放
我弟弟写C和C++,他看到我写PHP,变量从来不用释放,他说这么写代码真爽,你们就不担心内存泄漏吗?
与JAVA类似,PHP有一个很简单的垃圾收集器,它内部通过一个引用计算器对不再位于内存范围的对象进行垃圾收集管理,当某对象的引用计数器为0时,对象将被当作垃圾收集并从内存中删除,这种方式有一问题,如果两个对象之间存在着相互引用的关系,如“父对象-子对象”,这种情况下,即便父对象被垃圾回收,这些对象的引用计算器没有被收集,因此这些对象的只有等待脚本执行完成之后才能够进行释放,即使对父对象调用 unset()也不会释放在子对象中引用父对象的内存。 (参考http://bugs.php.net/bug.php?id=33595)示例如下:
<?php
class A {
    public $b;

    function __construct () {
        $this->b = new B($this);
    }
}

class B {
    public $parent;

    function __construct ($parent = NULL) {
        $this->parent = $parent;
    }
}

for ($i = 0 ; $i < 1000000 ; $i++) {
    $a = new A();
}
?>

我运行的结果是Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 32 bytes) in E:\eusite\php3\test.php on line 19
我将代码修改如下:
<?php
class A {
    function __construct () {
        $this->b = new B($this);
    }
}

class B {
    function __construct ($parent = NULL) {
        $this->parent = $parent;
    }
}

for ($i = 0 ; $i < 1000000 ; $i++) {
    $a = new A();
    unset($a);
}

//输出结果是:63,520。
echo number_format(memory_get_usage());
?>

这里我采用手动unset的方式释放父对象内存,表面上看似我手动将对象内存释放,但是如果我们将测试代码改成下面这样:
<?php
class A {
    function __construct () {
        $this->b = new B($this);
    }
}

class B {
    function __construct ($parent = NULL) {
        $this->parent = $parent;
    }
}

for ($i = 0 ; $i < 1000000 ; $i++) {
    $a = new A();
    unset($a);
    echo number_format(memory_get_usage()) . "<br>";
}
?>

输出结果如下:
62,400
62,800
63,176
63,552
...
33,550,992
33,551,368
33,551,744
33,552,120
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 42 bytes) in E:\eusite\php3\test.php on line 10
你会发现输出值一个比一个大,证明我们在unset对象的时候并没有释放A类中对B类的引用的内存,如若不然,数值的输出应该是一样的。http://bugs.php.net/bug.php?id=33595中提到了一种解决方案:
<?php
class A {
    function __construct () {
        $this->b = new B($this);
    }

	function __destruct(){
		unset($this->b);
	}
}

class B {
    function __construct ($parent = NULL) {
        $this->parent = $parent;
    }
}

for ($i = 0 ; $i < 1000000 ; $i++) {
    $a = new A();
    $a->__destruct();
    unset($a);
    echo number_format(memory_get_usage()) . "<br>";
}
?>

输出结果如下:
63,496
63,496
...
63,496
63,496
end
63,496

在上述情况下每当创建 A 类的实例并且该实例随后超出内存范围时,内存不会被释放,因此脚本在内存使用中不断增加,只有为父类创建一个解构函数将直接释放子对象,这种解构器必须在解除父类引用之前进行调用,执行这些代码那就跟写C、C++没啥区别了。
PHP V5.3解决了这个问题,垃圾收集器将检测这些循环引用,并且能够释放它们所占用的内存,因此在执行脚本时 PHP 内存使用情况将保持平稳。当A类的每个引用被删除后,A类中的B类引用也将会被当作垃圾收集。这种循环垃圾收集的方式使得PHP OOP的性能将获得大大的提升,改善内存使用做出不可磨灭的贡献。

6、新添闭包和反射以及lambda函数的支持
最JS前端开发的程序员和Python 和 Ruby开发者,对这两者应该不陌生。比如JavaScript中使用闭包方式构建对象。在PHP V3中添加了闭包和lambda的支持,这意味着函数可以动态创建并作为参数传递给其他方法。

1)闭包
通过闭包,我们可以进一步将逻辑封装到一个指定范围,在很小的范围内在绑定的特定函数。写过Ruby代码的人应该都知道Ruby 中的闭包使用的魔法表现,这里举一个很实用的例子。
<?php
class Logger{
	public static $mes = array();

	public static function log($code,$string){
		self::$mes[] = "[$code]:".$string; 
	}
}

class Blog{

	public function __construct(){
	}

	public function addComment($id,$data){
		$sql = sprintf( "INSERT INTO comments SET blog_id=%d,user_id=%d,content='%s'",$id,$data['user_id'],$data['content']);
		Logger::log('database',$sql);
		$sql = sprintf( "UPDATE blogs SET comments=comments+1 WHERE id=%d",$id );
		Logger::log('database',$sql);
		$sql = sprintf( "UPDATE users SET comments=comments+1 WHERE id=%d",$data['user_id'] );
		Logger::log('database',$sql);
	}
}

$blog = new Blog();
$blog->addComment(1,array(
	'user_id' => 1,
	'content' => 'hello',
));

print_r(Logger::$mes);
?>

上述代码中,每次记录日志都得调用Logger::log静态方法,一旦Logger::log的参数变化,就必须挨个挨个改变代码,下面改用闭包的方式实现将日志记录的封装到addComment方法的本身范围内。
<?php
class Logger{
	public static $mes = array();

	public static function log($code,$string){
		self::$mes[] = "[$code]:".$string; 
	}
}

class Blog{

	public function __construct(){
	}

	public function addComment($id,$data){
		$code = 'database';
		$log = function ($sql) use ($code) { Logger::log($code,$sql); };
		$sql = sprintf( "INSERT INTO comments SET blog_id=%d,user_id=%d,content='%s'",$id,$data['user_id'],$data['content']);
		$log($sql);
		$sql = sprintf( "UPDATE blogs SET comments=comments+1 WHERE id=%d",$id );
		$log($sql);
		$sql = sprintf( "UPDATE users SET comments=comments+1 WHERE id=%d",$data['user_id'] );
		$log($sql);
	}
}

$blog = new Blog();
$blog->addComment(1,array(
	'user_id' => 1,
	'content' => 'hello',
));

print_r(Logger::$mes);
?>

也可以将闭包用在类对象中,类中定义的闭包基本上与在对象外部定义的闭包相同,惟一的不同之处在于通过 $this 变量自动导入对象,我们可以在类闭包中通过$this->name的方式访问类中name成员变量;我们还可以通过将闭包定义为静态闭包,这样与类中定义闭包的区别在于后者将不再将$this变量传入到闭包中。比如:
<?php
class Test{
	$name = 'kokko';

	function doAct($act){
		return function() use $act{
			return $act.','.$this->name;
		}
	}
}

$test = new Test();
echo $test->doAct('hi');	//输出hi,kokko
?>

如果在闭包function前面加上static关键字'return static function() user $act',那么闭包代码将不能访问类Test中的name属性了,通常我们只有在不使用类本身成员属性的情况下才将闭包声明为static静态闭包,因为它不需要将对象应用导入闭包中,可以节省内存。我们可以通过 __invoke() 方法来将类本身用作闭包。
<?php
class Test
{
    public function __invoke()
    {
         return "Hi,I am kokko";
    }
}

$test = new Test();
echo $test();	//输出'Hi,I am kokko'
?>


2)lambda函数
俗称匿名函数,是可以随时定义的简单抛弃型函数,函数本身仅存在于定义函数的变量范围内,因此当该变量超出范围时,函数也随之失效,有点类似函数中局部变量的意思。
早在PHP4中我们就可以通过create_function来实现匿名函数了,但是该方法并不太友好,并不适合太多代码的封装,感兴趣的朋友可以去看看PHP的手册相关章节,而PHP V3正式开始了对匿名函数的支持,我们以前实现匿名函数的方式有了很大的变化。
<?php
$av = array("the ", "a ", "that ", "this ");
$fcstr = '$v = $v . "mango";';
array_walk($av, create_function('&$v,$k',$fcstr ));
print_r($av); 
?>

假如在create_function函数中代码存在稍微复杂一点的逻辑,比如弄几个if else,这代码就会相当的不便,PHP V5.3中我们可以这么写:
<?php
$av = array("the ", "a ", "that ", "this ");
array_walk($av,function(&$v,$k){
	$v = $v.'mango';
});
print_r($av); 
?>

代码可阅读性更强,如果代码中出现if、else等判断也不会造成编码的不便。

3)反射
JAVA程序员应该很熟悉反射这个词,现在PHP V5.3也支持对象反射和方法反射,它允许我们对类、接口、函数和方法执行反向工程。我们通过ReflectionMethod 和 ReflectionFunction、 ReflectionClass类中getClosure() 方法可以实现类、函数方法的反向工程。
<?php
class Test{
	public $name = 'kokko';

	public function setName($name){
		$this->name = $name;
	}

	public function getName(){
		return $this->name;
	}
}
$class = new ReflectionClass('Test');
$method = $class->getMethod('getName');
$closure = $method->getClosure();
echo $closure();	//output 'kokko'
$class->setName('won');
echo $closure();	//output 'won'
?>

通过反射我们还可以访问类的私有方法,可以内省闭包,将反射 API 能够通过现有函数和方法动态创建闭包,从而为闭包提供强大的支持。
<?php
$closure = function ($x, $y = 1) {}; 
$m = new ReflectionMethod($closure); 
Reflection::export ($m);
//output
/*
Method [ <internal> public method __invoke ] {
  - Parameters [2] {
    Parameter #0 [ <required> $x ]
    Parameter #1 [ <optional> $y ]
  }
}
*/
?>


7、goto的支持
PHP V5.3中添加了像VB中的goto的支持直接跳过一段代码执行
<?php
$headers = Array('subject', 'bcc', 'to', 'cc', 'date', 'sender');
$position = 0;

hIterator: {
    $c = 0;
    echo $headers[$position] . PHP_EOL;

    cIterator: {
        echo ' ' . $headers[$position][$c] . PHP_EOL;

        if(!isset($headers[$position][++$c])) {
            goto cIteratorExit;
        }
        goto cIterator;
    }

    cIteratorExit: {
        if(isset($headers[++$position])) {
            goto hIterator;
        }
    }
}
?>


8、命名空间
PHP 5.3中开始更全面的OOP支持,为了帮助组织大型的代码库,添加namespace关键字支持命名空间。我们可以通过 namespace来声明一个命名空间来更好的组织我们的代码,而不会引起类的命名冲突问题,值得注意的是namespace的声明必须是文件中的第一个命令或输出。
<?php 
namespace core; 
class app {
} 
?> 

使用带有名称空间的代码
<coolcode lang="php" download="app.php">
<?php
namespace eu;
include('core/app.php');
class App extends core\App{
}
?>

在名称空间内调用函数
<?php 
namespace comm; 
function doSomething(){
    echo "comm.doSomthing";
}
?> 

<?php 
namespace user; 
function doSomething(){
    echo "user.doSomthing";
}
?> 

<?php 
include 'comm.php'; 
use comm; 
doSomething(); // outputs "comm.doSomthing"; 
?> 

<?php
include 'comm.php';
include 'user.php';
comm\doSomething(); // outputs "comm.doSomthing";
user\doSomething(); // outputs "user.doSomthing";
?>


9、使用Phar归档
Phar归档的概念来自Java中JAR归档,它允许使用单个文件打包应用程序,这个文件中包含运行应用程序所需的所有东西。关于该特性CoolPHP中还没有涉及到相关的应用,所以也不做更多是示例说明。有兴趣的朋友可以Google一下,应该有不少资料!

原文:http://www.kokkowon.com/archives/902
分享到:
评论

相关推荐

    PHP5.3新特性

    以下是根据文件提供的信息,对PHP5.3新特性知识点的详细总结: 1. 命名空间的引入 命名空间是PHP5.3中最大的一个新增功能。它为PHP的代码库提供了一个完整的命名空间实现。在命名空间中,大部分功能是在编译时实现...

    PHP5.3到7的特性总结

    ### PHP5.3到PHP7的新特性总结 随着PHP版本的不断迭代,其语言特性也得到了显著增强。本文将从PHP5.3升级至PHP7的过程中遇到的一些关键变化出发,详细解析这些变化带来的影响以及如何应对。 #### PHP5.3到PHP7的...

    PHP5.3新特性小结

    以下将详细介绍PHP5.3的一些关键新特性: 1. **命名空间(Namespaces)** 命名空间是PHP5.3引入的重要特性,它为了解决在大型项目中可能出现的类、函数和常量命名冲突问题。通过命名空间,我们可以将相关的类和...

    php5.3 5.4 redis.all

    总结来说,"php5.3 5.4 redis.all" 是关于在PHP 5.3和5.4版本中集成和使用Redis的资源,涉及到`phpredis`扩展的安装、配置以及使用基本的Redis命令。在不同PHP版本间,开发者需要注意语言特性和性能上的差异,以充分...

    php_memcache-5.2 5.3 5.4

    总结,php_memcache是PHP与Memcached集成的关键,通过正确配置和优化,可以极大地提升Web应用的响应速度。了解其工作原理、使用方法以及常见优化策略,对于任何使用PHP进行Web开发的程序员来说都是必不可少的知识点...

    ZendGuardLoader-php-5.3-Windows.zip

    总结来说,"ZendGuardLoader-php-5.3-Windows.zip" 是一套用于在Windows环境下保护和优化PHP 5.3代码的工具,通过加密源代码以确保代码的安全,并提供运行时优化以提升性能。安装和使用这个工具需要对PHP环境有一定...

    php_memcacth.dll 2.2.6 (版本号5.3)

    php_memcache.dll 2.2.6 版本确保了与PHP 5.3系列的兼容性,这意味着开发者可以充分利用PHP 5.3的新特性,同时享受Memcached带来的高性能缓存服务。但需要注意的是,由于PHP版本的不断更新,对于较新的PHP版本,可能...

    一键lnmp(nginx1.6.2+mysql5.1+php5.3)-详细笔记文档总结

    本笔记文档将详细介绍如何在Linux系统上快速安装和配置Nginx 1.6.2、MySQL 5.1和PHP 5.3,以构建一个高效、稳定的一键式LNMP环境。 一、Nginx介绍 Nginx是一款高性能的HTTP和反向代理服务器,以其轻量级、高并发...

    PHP 5.3.10 for Linux.zip

    PHP 5.3版本引入了许多重要的新特性和改进,包括: - **命名空间(Namespaces)**:这是PHP 5.3引入的一个核心特性,允许在代码中组织类、接口和函数,避免了命名冲突,提高了代码的可维护性。 - ** Late Static ...

    wordpress-php-5.3:在 PHP 5.3 上运行 WordPress 的开发设置

    你可以使用`php5.3`或`php5.3-cli`命令(取决于你的系统)来执行PHP脚本。确保安装了所有必需的扩展,例如MySQLi(用于数据库连接)和gd库(用于图像处理)。 接下来,你需要设置WordPress的数据库连接。在wp-...

    一键lnmp(mysql分离)(nginx 1.13+mysql5.5+php5.3)-详细笔记文档总结-带安装包

    PHP 5.3版本引入了命名空间、Late Static Bindings和闭包等新特性,提升了代码的组织和可维护性。安装PHP时,可以使用php-fpm(FastCGI进程管理器)与Nginx配合,提高PHP处理请求的效率。同样,我们需要配置php.ini...

    一键lnmp(nginx 1.13+mysql5.5+php5.3)

    PHP 5.3是PHP语言的一个版本,引入了许多新的特性和改进: 1. **命名空间**:引入了命名空间,有助于解决大型项目中的类名冲突问题。 2. ** Late Static Bindings**:允许静态方法调用时引用实际调用类,而非定义时...

    PHP实例开发源码—PHPvod Studio 视频点播系统for php5.3.x GBK.zip

    PHPvod Studio 是一个基于 PHP 语言开发的视频点播系统,专为 PHP5.3.x 版本设计,支持GBK编码,提供了丰富的功能和良好的用户体验。在这个系统中,我们可以深入学习到PHP在构建动态网站,尤其是多媒体流媒体服务...

    ECShop商城系统ecshopv2.7.3支持PHP5.3 5.4 5.5等版本

    总结来说,ECShop v2.7.3是面向PHP 5.3以上版本的一个成熟电商解决方案,具有全面的电商功能和良好的扩展性。但为了保证系统的安全性和稳定性,开发者应当考虑升级到更现代的PHP版本,并定期进行安全更新和维护。...

    Laravel5.3正文文档

    - **Laravel 5.3 新特性**:Laravel 5.3 在 5.2 的基础上进行了大量的改进和新增功能,包括但不限于: - 基于驱动的通知系统,允许开发者轻松地通过邮件、短信或第三方服务(如 Slack)发送通知。 - Laravel Echo ...

    php 5.3.0 x64 64位 PHP X64 64位

    - **命名空间(Namespaces)**:这是PHP 5.3引入的一个重要特性,使得代码组织更加有序,支持类、函数和常量的分层命名。 - **闭包(Closures/Lambda Functions)**:提供了匿名函数的支持,使得函数可以作为值...

    PHP中memcache扩展 5.2和5.3版本

    而PHP 5.3则在2009年发布,引入了命名空间、 Late Static Bindings、闭包(Closures)等新特性,进一步提升了PHP作为面向对象编程语言的能力。对于这两个版本的PHP,其对应的Memcache扩展可能在函数签名、API或性能...

    使用pthreads实现真正的PHP多线程(需PHP5.3以上版本)

    标题中的“使用pthreads实现真正的PHP多线程(需PHP5.3以上版本)”指的是在PHP编程中利用pthreads扩展来实现多线程功能。pthreads是PHP的一个非标准扩展,它允许开发者在PHP环境中创建和管理线程,从而提高程序的...

    基于PHP的vod 视频点播系统源码for 5.3.x UTF-8.zip

    该源码是针对PHP 5.3.x版本设计的,这一版本在PHP历史中占有重要地位,引入了许多新特性,如命名空间、闭包等,提升了代码的组织性和可维护性。同时,源码使用UTF-8编码,这是一种广泛支持的多字节字符集,能处理...

Global site tag (gtag.js) - Google Analytics