확장 생성
의심할 여지 없이 눈치채셨듯이 모든 PHP 확장에는 매우 일반적이고 매우 단조로운 구조 및 파일. 새 확장 개발을 시작할 때 이러한 공통 구조가 이미 존재하는 경우에만 기능 코드를 채우는 것을 고려하는 것이 좋습니다.
ext_skel
PHP 소스 코드 트리로 전환 ext/ 디렉토리에서 다음 명령을 실행합니다:
jdoe@devbox:/home/jdoe/cvs/php-src/ext/$ ./ext_skel extname=sample7
잠깐만 기다리면 다음과 같은 결과가 출력됩니다.
To use your new extension, you will have to execute the following steps: 1. $ cd .. 2. $ vi ext/sample7/config.m4 3. $ ./buildconf 4. $ ./configure [with|enable]-sample7 5. $ make 6. $ ./php -f ext/sample7/sample7.php 7. $ vi ext/sample7/sample7.c 8. $ make Repeat steps 3-6 until you are satisfied with ext/sample7/config.m4 and step 6 confirms that your module is compiled into PHP. Then, start writing code and repeat the last two steps as often as necessary.
이제 ext/sample7 디렉토리를 보면 5장의 "첫 번째 확장"에서 작성한 확장 뼈대 코드를 볼 수 있습니다. 단지 아직 컴파일할 수는 없지만 만들기만 하면 됩니다. config.m4를 약간 수정하여 작동하게 하면 5장에서 수행한 대부분의 작업을 피할 수 있습니다.
함수 프로토타입 생성
타사 라이브러리용 래퍼 확장을 작성하는 경우 추가 전달을 통해 머신 규모 버전의 프로토타입에 대한 함수 설명(헤더 파일)이 이미 있습니다. ./ext_skel에 인수를 추가하면 자동으로 헤더 파일을 스캔하고 인터페이스에 해당하는 간단한 PHP_FUCNTION() 블록을 생성합니다. 사용 방법은 다음과 같습니다. ./ext_skel 지시어는 zlib 헤더를 구문 분석합니다:
jdoe@devbox:/home/jdoe/cvs/php-src/ext/$ ./ext_skel extname=sample8 \ proto=/usr/local/include/zlib/zlib.h
이제 ext/sample8/sample8.c에서 각 zlib 함수에 대해 하나씩 많은 PHP_FUNCTION() 정의를 볼 수 있습니다. 스켈레톤 생성기는 일부 알 수 없는 리소스 유형에 대해 경고 메시지를 생성합니다. 이러한 기능에 특별한 주의를 기울이고 이러한 내부 복잡한 구조를 사용자 공간 액세스 가능한 변수와 연결하려면 9장 "리소스 데이터 유형"에서 배운 내용을 사용해야 할 수도 있습니다.
PECL_Gen
더 완전한 코드 생성기가 있지만 더 복잡한 코드 생성기도 있습니다: PECL_Gen은 PECL에서 찾을 수 있습니다(http://www .php.cn/)이며 pear install PECL_Gen 명령을 사용하여 설치할 수 있습니다.
번역자 참고: PECL_Gen은 CodeGen_PECL(http://www.php.php)로 마이그레이션되었습니다. cn/) 이 장에는 CodeGen_PECL을 사용한 코드 테스트가 포함됩니다. 버전 정보는 "php 1.1.3, Copyright (c) 2003-2006 Hartmut Holzgraefe"입니다. 환경 사용에 문제가 있는 경우 번역자의 환경 구성을 참조하세요.
설치가 완료되면 ext_skel처럼 실행하거나 동일한 입력 매개변수를 수락하거나 거의 동일한 출력을 생성하거나 완전한 xml 정의 파일을 생성할 수 있습니다. 제공되면 더욱 강력하고 완벽하게 컴파일 가능한 확장 버전을 생성할 수 있습니다. PECL_Gen은 핵심 기능에 대한 확장 작성 시간을 절약하지 않고 확장된 뼈대 코드를 효율적으로 생성하는 선택적 방법을 제공합니다. 🎜>specfile.xml
다음은 가장 간단한 확장 정의 파일입니다:
아아아앙
译注: 请注意, 译者使用的原著中第一行少了后面的问号, 导致不能使用, 加上就OK.
通过PECL_Gen命令运行这个文件:
jdoe@devbox:/home/jdoe/cvs/php-src/ext/$ pecl-gen specfile.xml
则会产生一个名为sample9的扩展, 并暴露一个用户空间函数sample9_hello_world().
关于扩展
除了你已经熟悉的功能文件, PECL_Gen还会产生一个package.xml文件 它可以用于pear安装. 如果你计划发布包到PECL库, 或者哪怕你只是想要使用pear包系统交付内容, 有这个文件都会很有用.
总之, 你可以在PECL_Gen的specfile.xml中指定多数package.xml文件的元素.
<?xml version="1.0" encoding="UTF-8" ?> <extension name="sample9"> <summary>Extension 9 generated by PECL_Gen</summary> <description>Another sample of PHP Extension Writing</description> <maintainers> <maintainer> <name>John D. Bookreader</name> <email>jdb@example.com</email> <role>lead</role> </maintainer> </maintainers> <release> <version>0.1</version> <date>2006-01-01</date> <state>beta</state> <notes>Initial Release</notes> </release> ... </extension>
当PECL_Gen创建扩展时, 这些信息将被翻译到最终的package.xml文件中.
依赖
如你在第17章"配置和链接"中所见, 依赖可以扫描出来用于config.m4和config.w32文件. PECL_Gen可以使用13935679349a1ec3c6b24bf69d8dc011定义各种类型的依赖完成扫描工作. 默认情况下, 列在13935679349a1ec3c6b24bf69d8dc011标签下的依赖会同时应用到Unix和win32构建中, 除非显式的是否用platform属性指定某个目标
<?xml version="1.0" encoding="UTF-8" ?> <extension name="sample9"> ... <deps platform="unix"> <! UNIX specific dependencies > </deps> <deps platform="win32"> <! Win32 specific dependencies > </deps> <deps platform="all"> <! Dependencies that apply to all platforms > </deps> ... </extension>
with
通常, 扩展在配置时使用--enable-extname样式的配置选项. 通过增加一个或多个3f7bdb502a84bf1a14abe8c8945ca31d标签到13935679349a1ec3c6b24bf69d8dc011块中, 则不仅配置选项被修改为--with-extname, 而且同时需要扫描头文件:
deps platform="unix"> <with defaults="/usr:/usr/local:/opt" testfile="include/zlib/zlib.h">zlib headers</with> </deps>
库
必须的库也列在13935679349a1ec3c6b24bf69d8dc011下, 使用00074440385736cfd09597d9818e6839标签.
<deps platform="all"> <lib name="ssleay" platform="win32"/> <lib name="crypto" platform="unix"/> <lib name="z" platform="unix" function="inflate"/> </deps>
在前面两个例子中, 只是检查了库是否存在; 第三个例子中, 库将被真实的加载并扫描以确认inflate()函数是否定义.
尽管13935679349a1ec3c6b24bf69d8dc011标签实际已经命名了目标平台, 但00074440385736cfd09597d9818e6839标签也有一个platform属性可以覆盖13935679349a1ec3c6b24bf69d8dc011标签的platform设置. 当它们混合使用的时候要格外小心.
1aa9e5d373740b65a0cc8f0a02150c53
此外, 需要包含的文件也可以通过在13935679349a1ec3c6b24bf69d8dc011块中使用1aa9e5d373740b65a0cc8f0a02150c53标签在你的代码中追加一个#include指令列表. 要强制某个头先包含, 可以在1aa9e5d373740b65a0cc8f0a02150c53标签上增加属性prepend="yes". 和00074440385736cfd09597d9818e6839依赖类似, 1aa9e5d373740b65a0cc8f0a02150c53也可以严格限制平台:
<deps> <header name="sys/types.h" platform="unix" prepend="yes"/> <header name="zlib/zlib.h"/> </deps>
译注: 经测试, 译者的环境1aa9e5d373740b65a0cc8f0a02150c53标签不支持platform属性.
常量
用户空间常量使用7e75141f12bcfb6308da8eb0ac04b6c2块中的一个或多个826c8bb1a1396ec98291fb764e7d0752标签定义. 每个标签需要一个name和一个value属性, 以及一个值必须是int, float, string之一的type属性.
<constants> <constant name="SAMPLE9_APINO" type="int" value="20060101"/> <constant name="SAMPLE9_VERSION" type="float" value="1.0"/> <constant name="SAMPLE9_AUTHOR" type="string" value="John Doe"/> </constants>
全局变量
线程安全全局变量的定义方式几乎相同. 唯一的不同在于type参数需要使用C语言原型而不是php用户空间描述. 一旦定义并构建, 全局变量就可以使用第12章"启动, 终止, 以及其中的一些点"中学习的EXTNAME_G(global_name)的宏用法进行访问. 在这里, value属性表示变量在请求启动时的默认值. 要注意在specfile.xml中这个默认值只能指定为简单的标量数值. 字符串和其他复杂结构应该在RINIT阶段手动设置.
<globals> <global name="greeting" type="char *"/> <global name="greeting_was_issued" type="zend_bool" value="1"/> </globals>
INI选项
要绑定线程安全的全局变量到php.ini设置, 则需要使用7ff739baee71802d5a32f10ed81e75df标签而不是0605e9470624fea4d1cc217279bc6161. 这个标签需要两个额外的参数: onupdate="updatemethod"标识INI的修改应该怎样处理, access="mode"和第13章"INI设置"中介绍的模式含义相同, "mode"值可以是: all, user, perdir, system.
<globals> <phpini name="mysetting" type="int" value="42" onupdate="OnUpdateLong" access="all"/> </globals>
函数
你已经看到了最基本的函数定义; 不过, 8fd0b0dd077e9e3b89425c7034f15437标签在PECL_Gen的specfile中实际上支持两种不同类型的函数.
两个版本都支持你已经在d48e197d6ef23c023982d3f523fa26d2级别上使用过的631fb227578dfffda61e1fa4d04b7d25和8b55addfb40ddf4a384b1010d729e503属性; 两种类型都必须的元素是ffbe95d20f3893062224282accb13e8f标签, 它包含了将要被放入你的源代码文件中的原文C语言代码.
role="public"
如你所想, 所有定义为public角色的函数都将包装恰当的PHP_FUNCTION()头和花括号, 对应到扩展的函数表向量中的条目.
除了其他函数支持的标签, public类型还允许指定一个b59f493af26f496bf5bf5aa84cbcd7de标签. 这个标签的格式应该匹配php在线手册中的原型展示, 它将被文档生成器解析.
<functions> <function role="public" name="sample9_greet_me"> <summary>Greet a person by name</summary> <description>Accept a name parameter as a string and say hello to that person. Returns TRUE.</description> <proto>bool sample9_greet_me(string name)</proto> <code> <![CDATA[ char *name; int name_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { return; } php_printf("Hello "); PHPWRITE(name, name_len); php_printf("!\n"); RETURN_TRUE; ]]> </code> </function> </functions>
role="internal"
内部函数涉及5个zend_module_entry函数: MINIT, MSHUTDOWN, RINIT, RSHUTDOWN, MINFO. 如果指定的名字不是这5个之一将会产生pecl-gen无法处理的错误.
<functions> <function role="internal" name="MINFO"> <code> <![CDATA[ php_info_print_table_start(); php_info_print_table_header(2, "Column1", "Column2"); php_info_print_table_end(); ]]> </code> </function> </functions>
自定义代码
所有其他需要存在于你的扩展中的代码都可以使用ffbe95d20f3893062224282accb13e8f标签包含. 要放置任意代码到你的目标文件extname.c中, 使用role="code"; 或者说使用role="header"将代码放到目标文件php_extname.h中. 默认情况下, 代码将放到代码或头文件的底部, 除非指定了position="top"属性.
<code role="header" position="bottom"> <![CDATA[ typedef struct _php_sample9_data { long val; } php_sample9_data; ]]> </code> <code role="code" position="top"> <![CDATA[ static php_sample9_data *php_sample9_data_ctor(long value) { php_sample9_data *ret; ret = emalloc(sizeof(php_sample9_data)); ret->val = value; return ret; } ]]> </code>
译注: 译者的环境中不支持原著中ffbe95d20f3893062224282accb13e8f标签的name属性.
小结
使用本章讨论的工具, 你就可以快速的开发php扩展, 并且让你的代码相比手写更加不容易产生bug. 现在是时候转向将php嵌入到其他项目了. 剩下的章节中, 你将利用php环境和强大的php引擎为你的已有项目增加脚本能力, 使它可以为你的客户提供更多更有用的功能.
以上就是的内容,更多相关内容请关注PHP中文网(www.php.cn)!