例子代码来源于网页http://devzone.zend.com/article/1021,其原本是讲解如何编写PHP中的扩展(extension)的,在此提取了其中的部分代码,并增加了二个函数,用于对PHP中的non persistent/persistent resource进行尝试; 当然以下这部分代码也相对完整,可以独立进行编译及运行。
config.m4
php_hello.h
hello.c
在上面的代码中:
hello_person_new 会返回一个non persistent resource
hello_person_pnew 会返回一个persistent resource
最后二个函数是我新增加的,主要是为了说明当一个资源变量的属性改变后,其他资源变量中的相应属性的变化情况。
函数hello_person_update_age完成对资源属性age进行修改,而hello_person_update_age则返回age的值。
对以上代码的编译及运行:
1)新建一个目录,比如hello,并在hello目录中创建上面提到的三个文件:config.m4, php_hello.h, hello.c
2)进入hello目录,运行phpize命令, 会得到以下的输出:
Configuring for:
PHP Api Version: 20041225
Zend Module Api No: 20060613
Zend Extension Api No: 220060519
不同的PHP版本,得到的输出也会不同。此命令会生成一些后继步骤所需的文件,如configure等
3)./configure –enable-hello
4)make
成功编译后,会在当前目录的modules/子目录中生成hello.so
5)sudo cp modules/hello.so /usr/lib/php5/20060613+lfs/
把这个hello.so文件,拷贝到其它php扩展所在的目录,我的机器上(所装系统为Ubuntu 10.04)所在的目录为:/usr/lib/php5/20060613+lfs/,在这个目录中可以看到其它的一些文件如mysql.so, xdebug.so等(如果安装了这些扩展的话)
6)创建配置文件hello.ini, 并包含以下一行内容:
extension=hello.so
然后把这个hello.ini放在php其它配置文件所在的目录,我的PC上所在的目录为:/etc/php5/conf.d/,在此目录中可以看到其它一些文件如mysql.ini, xdebug.ini等(如果安装了这些扩展的话)
注:根据不同的系统配置及PHP安装的不同情况,可以把hello.so及hello.ini放置在其它的目录中,或者不创建hello.ini而把extension=hello.so放在其它的配置文件中,但做完这些步骤后,都可以通过以下的方式来检验是否配置正确:
A)命令行php –ini的输出中应该包含所创建的hello.ini
B)命令行php –m会列出所有的扩展,输出中有一行应该为hello
C)命令行php –re hello可以列出扩展的信息,输出为这个hello扩展中的信息
Extension [ <persistent> extension #44 hello version 1.0 ] {
- Functions {
Function [ <internal:hello> function hello_person_new ] {
}
Function [ <internal:hello> function hello_person_pnew ] {
}
Function [ <internal:hello> function hello_person_get_age ] {
}
Function [ <internal:hello> function hello_person_update_age ] {
}
}
}
7)如果打算在网页中使用这些函数,并且是用Apache作为web server的话,则需要重启一下web server
sudo /etc/init.d/apache2 restart
一切完毕后,我们就可以来使用这些函数了,在任一个php文件中:
$p1 = hello_person_new("John", 18);
$p2 = hello_person_new("John", 18); //具有相同的参数
hello_person_update_age($p1, 19); //把$p1的age属性修改掉
printf("Age of p1 is %d/n", hello_person_get_age($p1));
printf("Age of p2 is %d/n", hello_person_get_age($p2));
运行后输出为:
Age of p1 is 19
Age of p2 is 18
可以看到,对于non persistent resource,当对$p1的内容进行修改后,$p2的内容保持不变
再对persistent resource进行尝试:
$pp1 = hello_person_pnew("John", 18);
$pp2 = hello_person_pnew("John", 18); //具有相同的参数
hello_person_update_age($pp1, 19); //把$pp1的age属性修改掉
printf("Age of pp1 is %d/n", hello_person_get_age($pp1));
printf("Age of pp2 is %d/n", hello_person_get_age($pp2));
输出为:
Age of pp1 is 19
Age of pp2 is 19
可以看到,当对$pp1的内容进行修改后,$pp2的内容也会被修改
我们再在hello.c的以下一些函数的入口把函数名打印到终端或者文件中来查看其调用顺序(在上面的代码中没有包含这些打印语句)
php_hello_person_persist_dtor
php_hello_person_dtor
hello_person_new
hello_person_pnew
看一下这些resouce的dtor函数是在什么时候调用的。
并用以下的PHP代码进行测试:
$p1 = hello_person_new("Tom", 18);
$pp1 = hello_person_pnew("John", 18);
unset($p1);
unset($pp1);
$p2 = hello_person_new("Tom", 18);
$pp2 = hello_person_pnew("John", 18);
unset($p2);
unset($pp2);
如果我们在命令行运行以上的代码,得到的输出为:
Enter into hello_person_new with name = Tom
Enter into hello_person_pnew with name = John
Enter into php_hello_person_dtor
Enter into hello_person_new with name = Tom
Enter into hello_person_pnew with name = John
Enter into php_hello_person_dtor
Enter into php_hello_person_persist_dtor
可以看到,对于non persistent resource, 每当对变量进行unset时,其dtor (destructor)函数就会被调用;而对于persistent resource,只有在命令行结束时才调用了一次,这是为什么呢?
而如果我们以Apache作为web server, 在网页中运行上述内容,得到的trace内容为:
Enter into hello_person_new with name = Tom
Enter into hello_person_pnew with name = John
Enter into php_hello_person_dtor
Enter into hello_person_new with name = Tom
Enter into hello_person_pnew with name = John
Enter into php_hello_person_dtor
在这里,destructor函数一次都没有运行,但当我们尝试停止web server(命令:sudo /etc/init.d/apache2 stop)之后,才得到以下的trace:
Enter into php_hello_person_persist_dtor
原来,对于persistent resource, 一当申请,只有在其所在的扩展(extension)服务停止时,才会被释放。而PHP命令行退出,或者Web Server服务停止,都会导致其所有的extension都停止服务。这也是把这类resource称为persistent的原因。
罗嗦了一大堆,总结一下:
1)non persistent resource在调用unset之后,其destructor函数就会被调用,资源被释放;
2)而对于persistent resource, 当对一个变量调用unset时,资源并没有被释放,而只有当该扩展服务停止时,destructor函数才会被调用,资源才会真正被释放,当然也可以专门在扩展中增加一个函数,以强制释放persistent resource;
3)对于同一类的persistent resource变量,真正的资源只申请了一份;比如在本文的例子中,php_hello_person只申请了一份;