[Translation] [php extension development and embedded] Chapter 18 - Automatic generation of php extensions

黄舟
Release: 2023-03-05 16:40:01
Original
1598 people have browsed it


Extension generation

As you have undoubtedly noticed, every php extension contains some Very common and very monotonous structures and files. When starting the development of a new extension, it makes sense to only think about filling in the functional code if these common structures already exist. For this purpose, a Simple but very useful shell script.

ext_skel

Switch to your php source code tree ext/ In the directory, execute the following command:

jdoe@devbox:/home/jdoe/cvs/php-src/ext/$ ./ext_skel extname=sample7
Copy after login

Wait a moment and output some text. You will see the following output:

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.
Copy after login

Now look in the ext/sample7 directory, you will see the extension skeleton code you wrote in Chapter 5 "Your First Extension" Annotated version of . It's just that you can't compile it yet; but you only need to make a small modification to config.m4 to make it work, so you can avoid most of the work you did in Chapter 5.

Generate function prototype

#If you want to write a wrapper extension for a third-party library, then you already have a function Description (header file) of the machine-scale version of the prototype and basic behavior. By passing an extra argument to ./ext_skel, it will automatically scan your header file and create a simple PHP_FUCNTION() block corresponding to the interface. Here is how to use it The ./ext_skel directive parses the zlib header:

jdoe@devbox:/home/jdoe/cvs/php-src/ext/$ ./ext_skel extname=sample8 \
proto=/usr/local/include/zlib/zlib.h
Copy after login

Now in ext/sample8/sample8.c, you can see many PHP_FUNCTION() definitions, one for each zlib function. Be aware that the skeleton generator will generate warning messages for some unknown resource types. You will need to pay special attention to these functions, and in order to associate these internal complex structures with user-space accessible variables, you may need to use the What you learned in Chapter 9 "Resource Data Types".

PECL_Gen

There is a more complete but There is also a more complex code generator: PECL_Gen, which can be found in PECL (http://www.php.cn/) and can be installed using the pear install PECL_Gen command.

Translator's Note: PECL_Gen has been migrated to CodeGen_PECL (http://www.php.cn/). This chapter involves code testing using CodeGen_PECL. The version information is: "php 1.1.3, Copyright (c) 2003-2006 Hartmut Holzgraefe", if you have problems using the environment, please refer to the translator's environment configuration in the translation sequence.

Once the installation is complete, it can run like ext_skel, accept The same input parameters, produce roughly the same output, or if a complete xml definition file is provided, produce a more robust and fully compilable version of the extension. PECL_Gen does not save you time writing extensions to the core functionality; rather Provides an optional way to efficiently generate extended skeleton code.

specfile.xml

The following is the most Simple extension definition file:

<?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>
Copy after login




译注: 请注意, 译者使用的原著中第一行少了后面的问号, 导致不能使用, 加上就OK.

通过PECL_Gen命令运行这个文件:

jdoe@devbox:/home/jdoe/cvs/php-src/ext/$ pecl-gen specfile.xml
Copy after login

则会产生一个名为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>
Copy after login

当PECL_Gen创建扩展时, 这些信息将被翻译到最终的package.xml文件中.

依赖

如你在第17章"配置和链接"中所见, 依赖可以扫描出来用于config.m4和config.w32文件. PECL_Gen可以使用定义各种类型的依赖完成扫描工作. 默认情况下, 列在标签下的依赖会同时应用到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>
Copy after login

with

通常, 扩展在配置时使用--enable-extname样式的配置选项. 通过增加一个或多个标签到块中, 则不仅配置选项被修改为--with-extname, 而且同时需要扫描头文件:

deps platform="unix">
    <with defaults="/usr:/usr/local:/opt"
        testfile="include/zlib/zlib.h">zlib headers</with>
</deps>
Copy after login

必须的库也列在下, 使用标签.

<deps platform="all">
    <lib name="ssleay" platform="win32"/>
    <lib name="crypto" platform="unix"/>
    <lib name="z" platform="unix" function="inflate"/>
</deps>
Copy after login

在前面两个例子中, 只是检查了库是否存在; 第三个例子中, 库将被真实的加载并扫描以确认inflate()函数是否定义.

尽管标签实际已经命名了目标平台, 但标签也有一个platform属性可以覆盖标签的platform设置. 当它们混合使用的时候要格外小心.

此外, 需要包含的文件也可以通过在块中使用

标签在你的代码中追加一个#include指令列表. 要强制某个头先包含, 可以在
标签上增加属性prepend="yes". 和依赖类似,
也可以严格限制平台:

<deps>
    <header name="sys/types.h" platform="unix" prepend="yes"/>
    <header name="zlib/zlib.h"/>
</deps>
Copy after login

译注: 经测试, 译者的环境

标签不支持platform属性.

常量

用户空间常量使用块中的一个或多个标签定义. 每个标签需要一个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>
Copy after login

全局变量

线程安全全局变量的定义方式几乎相同. 唯一的不同在于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>
Copy after login

INI选项

要绑定线程安全的全局变量到php.ini设置, 则需要使用标签而不是. 这个标签需要两个额外的参数: 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>
Copy after login

函数

你已经看到了最基本的函数定义; 不过, 标签在PECL_Gen的specfile中实际上支持两种不同类型的函数.

两个版本都支持你已经在级别上使用过的

属性; 两种类型都必须的元素是标签, 它包含了将要被放入你的源代码文件中的原文C语言代码.

role="public"

如你所想, 所有定义为public角色的函数都将包装恰当的PHP_FUNCTION()头和花括号, 对应到扩展的函数表向量中的条目.

除了其他函数支持的标签, public类型还允许指定一个标签. 这个标签的格式应该匹配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>
Copy after login

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>
Copy after login

自定义代码

所有其他需要存在于你的扩展中的代码都可以使用标签包含. 要放置任意代码到你的目标文件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>
Copy after login

译注: 译者的环境中不支持原著中标签的name属性.

小结

使用本章讨论的工具, 你就可以快速的开发php扩展, 并且让你的代码相比手写更加不容易产生bug. 现在是时候转向将php嵌入到其他项目了. 剩下的章节中, 你将利用php环境和强大的php引擎为你的已有项目增加脚本能力, 使它可以为你的客户提供更多更有用的功能.

以上就是的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Related labels:
php
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template