Erweiterungsgenerierung
Wie Sie zweifellos bemerkt haben, enthält jede PHP-Erweiterung einige sehr häufige und sehr häufige Wenn Sie mit der Entwicklung einer neuen Erweiterung beginnen, ist es sinnvoll, nur dann über das Ausfüllen des Funktionscodes nachzudenken, wenn diese gemeinsamen Strukturen bereits vorhanden sind.
ext_skel
Wechseln Sie zu Ihrem PHP-Quellcodebaum ext/ Führen Sie im Verzeichnis den folgenden Befehl aus:
jdoe@devbox:/home/jdoe/cvs/php-src/ext/$ ./ext_skel extname=sample7
Warten Sie einen Moment und geben Sie einen Text aus. Sie sehen die folgende Ausgabe:
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.
Schauen Sie sich nun das Verzeichnis ext/sample7 an. Sie werden sehen, dass Sie in Kapitel 5 „Ihre erste Erweiterung“ eine kommentierte Version des erweiterten Grundcodes geschrieben haben. Sie können ihn nur noch nicht kompilieren um ein paar Änderungen an config.m4 vorzunehmen, damit es funktioniert, damit Sie den Großteil der Arbeit, die Sie in Kapitel 5 erledigt haben, vermeiden können.
Funktionsprototyp generieren
Wenn Sie eine Wrapper-Erweiterung für eine Bibliothek eines Drittanbieters schreiben möchten, benötigen Sie einen Funktionsprototyp und eine Beschreibung (Header-Datei) einer Maschinenversion des Grundverhaltens Durch die Übergabe eines zusätzlichen Arguments an ./ext_skel wird Ihre Header-Datei automatisch gescannt und ein einfacher PHP_FUCNTION()-Block erstellt, der der Schnittstelle entspricht. Im Folgenden wird die ./ext_skel-Direktive zum Parsen des zlib-Headers verwendet:
jdoe@devbox:/home/jdoe/cvs/php-src/ext/$ ./ext_skel extname=sample8 \ proto=/usr/local/include/zlib/zlib.h
Jetzt können Sie in ext/sample8/sample8.c viele PHP_FUNCTION()-Definitionen sehen, für jede gibt es eine zlib-Funktion. Beachten Sie, dass der Skelettgenerator eine Warnung generiert Sie müssen diesen Funktionen besondere Aufmerksamkeit schenken und um diese internen komplexen Strukturen mit vom Benutzer zugänglichen Variablen zu verknüpfen, müssen Sie möglicherweise das verwenden, was Sie in Kapitel 9 „Ressourcendatentypen“ gelernt haben.
PECL_Gen
Es gibt auch einen vollständigeren, aber komplexeren Codegenerator: PECL_Gen, der in zu finden ist PECL (http://www.php.cn/) und kann mit dem Befehl „pear install PECL_Gen“ installiert werden
Anmerkung des Übersetzers: PECL_Gen wurde auf CodeGen_PECL (http ://www.php.cn/). Die Versionsinformationen von CodeGen_PECL, die in diesem Kapitel zum Testen des Codes verwendet werden, lauten: „php 1.1.3, Copyright (c) 2003-2006 Hartmut Holzgraefe“, wenn Sie Probleme bei der Verwendung der Umgebung haben, Bitte beachten Sie die Umgebungskonfiguration des Übersetzers in der Übersetzungssequenz.
Sobald die Installation abgeschlossen ist, kann sie wie ext_skel ausgeführt werden, akzeptiert dieselben Eingabeparameter und erzeugt ungefähr die gleiche Ausgabe , oder wenn eine vollständige XML-Definitionsdatei bereitgestellt wird, wird eine robustere und vollständig kompilierbare Version der Erweiterung erstellt. PECL_Gen erspart Ihnen nicht das Schreiben der Erweiterungskernfunktion, sondern bietet eine optionale Möglichkeit, erweiterten Skelettcode effizient zu generieren.
specfile.xml
Das Folgende ist die einfachste Erweiterungsdefinitionsdatei:
<?xml version="1.0" encoding="utf-8" ?> <extension name="sample9"> <functions> <function name="sample9_hello_world" role="public"> <code> <![CDATA[ php_printf("Hello World!"); ]]> </code> </function> </functions> </extension>
译注: 请注意, 译者使用的原著中第一行少了后面的问号, 导致不能使用, 加上就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可以使用
<?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样式的配置选项. 通过增加一个或多个
deps platform="unix"> <with defaults="/usr:/usr/local:/opt" testfile="include/zlib/zlib.h">zlib headers</with> </deps>
库
必须的库也列在
<deps platform="all"> <lib name="ssleay" platform="win32"/> <lib name="crypto" platform="unix"/> <lib name="z" platform="unix" function="inflate"/> </deps>
在前面两个例子中, 只是检查了库是否存在; 第三个例子中, 库将被真实的加载并扫描以确认inflate()函数是否定义.
尽管
此外, 需要包含的文件也可以通过在
<deps> <header name="sys/types.h" platform="unix" prepend="yes"/> <header name="zlib/zlib.h"/> </deps>
译注: 经测试, 译者的环境
常量
用户空间常量使用
<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设置, 则需要使用
<globals> <phpini name="mysetting" type="int" value="42" onupdate="OnUpdateLong" access="all"/> </globals>
函数
你已经看到了最基本的函数定义; 不过,
两个版本都支持你已经在标签, 它包含了将要被放入你的源代码文件中的原文C语言代码.
role="public"
如你所想, 所有定义为public角色的函数都将包装恰当的PHP_FUNCTION()头和花括号, 对应到扩展的函数表向量中的条目.
除了其他函数支持的标签, public类型还允许指定一个
<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>
自定义代码
所有其他需要存在于你的扩展中的代码都可以使用标签包含. 要放置任意代码到你的目标文件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>
译注: 译者的环境中不支持原著中标签的name属性.
小结
使用本章讨论的工具, 你就可以快速的开发php扩展, 并且让你的代码相比手写更加不容易产生bug. 现在是时候转向将php嵌入到其他项目了. 剩下的章节中, 你将利用php环境和强大的php引擎为你的已有项目增加脚本能力, 使它可以为你的客户提供更多更有用的功能.
以上就是的内容,更多相关内容请关注PHP中文网(www.php.cn)!