首页 后端开发 php教程 [翻译][php扩展开发和嵌入式]第18章-php的扩展自动生成

[翻译][php扩展开发和嵌入式]第18章-php的扩展自动生成

Feb 10, 2017 am 10:36 AM
php


扩展生成

毫无疑问你已经注意到, 每个php扩展都包含一些非常公共的并且非常单调的结构和文件. 当开始一个新扩展开发的时候, 如果这些公共的结构已经存在, 我们只用考虑填充功能代码是很有意义的. 为此, 在php中包含了一个简单但是很有用的shell脚本.

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中, 你就可以看到许多PHP_FUNCTION()定义, 每个zlib函数对应一个. 要注意, 骨架生成程序会对某些未知资源类型产生警告消息. 你需要对这些函数特别注意, 并且为了将这些内部的复杂结构体和用户空间可访问的变量关联起来, 可能会需要使用你在第9章"资源数据类型"中学到的知识.

PECL_Gen

还有一种更加完善但也更加复杂的代码生成器: PECL_Gen, 可以在PECL(http://www.php.cn/)中找到它, 使用pear install PECL_Gen命令可以安装它.

译者注: PECL_Gen已经迁移为CodeGen_PECL(http://www.php.cn/). 本章涉及代码测试使用CodeGen_PECL的版本信息为: "php 1.1.3, Copyright (c) 2003-2006 Hartmut Holzgraefe", 如果您的环境使用有问题, 请参考译序中译者的环境配置.

一旦安装完成, 它就可以像ext_skel一样运行, 接受相同的输入参数, 产生大致相同的输出, 或者如果提供了一个完整的xml定义文件, 则产生一个更加健壮和完整可编译版本的扩展. PECL_Gen并不会节省你编写扩展核心功能的时间; 而是提供一种可选的方式高效的生成扩展骨架代码.

specfile.xml

下面是最简单的扩展定义文件:

<?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可以使用定义各种类型的依赖完成扫描工作. 默认情况下, 列在标签下的依赖会同时应用到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样式的配置选项. 通过增加一个或多个标签到块中, 则不仅配置选项被修改为--with-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()函数是否定义.

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

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

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

<deps>
    <header name="sys/types.h" platform="unix" prepend="yes"/>
    <header name="zlib/zlib.h"/>
</deps>
登录后复制

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

标签不支持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>
登录后复制

全局变量

线程安全全局变量的定义方式几乎相同. 唯一的不同在于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设置, 则需要使用标签而不是. 这个标签需要两个额外的参数: 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>
登录后复制

函数

你已经看到了最基本的函数定义; 不过, 标签在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>
登录后复制

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)!


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 Dec 24, 2024 pm 04:42 PM

PHP 8.4 带来了多项新功能、安全性改进和性能改进,同时弃用和删除了大量功能。 本指南介绍了如何在 Ubuntu、Debian 或其衍生版本上安装 PHP 8.4 或升级到 PHP 8.4

我后悔之前不知道的 7 个 PHP 函数 我后悔之前不知道的 7 个 PHP 函数 Nov 13, 2024 am 09:42 AM

如果您是一位经验丰富的 PHP 开发人员,您可能会感觉您已经在那里并且已经完成了。您已经开发了大量的应用程序,调试了数百万行代码,并调整了一堆脚本来实现操作

如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 Dec 20, 2024 am 11:31 AM

Visual Studio Code,也称为 VS Code,是一个免费的源代码编辑器 - 或集成开发环境 (IDE) - 可用于所有主要操作系统。 VS Code 拥有针对多种编程语言的大量扩展,可以轻松编写

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

php程序在字符串中计数元音 php程序在字符串中计数元音 Feb 07, 2025 pm 12:12 PM

字符串是由字符组成的序列,包括字母、数字和符号。本教程将学习如何使用不同的方法在PHP中计算给定字符串中元音的数量。英语中的元音是a、e、i、o、u,它们可以是大写或小写。 什么是元音? 元音是代表特定语音的字母字符。英语中共有五个元音,包括大写和小写: a, e, i, o, u 示例 1 输入:字符串 = "Tutorialspoint" 输出:6 解释 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。总共有 6 个元

您如何在PHP中解析和处理HTML/XML? 您如何在PHP中解析和处理HTML/XML? Feb 07, 2025 am 11:57 AM

本教程演示了如何使用PHP有效地处理XML文档。 XML(可扩展的标记语言)是一种用于人类可读性和机器解析的多功能文本标记语言。它通常用于数据存储

解释PHP中的晚期静态绑定(静态::)。 解释PHP中的晚期静态绑定(静态::)。 Apr 03, 2025 am 12:04 AM

静态绑定(static::)在PHP中实现晚期静态绑定(LSB),允许在静态上下文中引用调用类而非定义类。1)解析过程在运行时进行,2)在继承关系中向上查找调用类,3)可能带来性能开销。

什么是PHP魔术方法(__ -construct,__destruct,__call,__get,__ set等)并提供用例? 什么是PHP魔术方法(__ -construct,__destruct,__call,__get,__ set等)并提供用例? Apr 03, 2025 am 12:03 AM

PHP的魔法方法有哪些?PHP的魔法方法包括:1.\_\_construct,用于初始化对象;2.\_\_destruct,用于清理资源;3.\_\_call,处理不存在的方法调用;4.\_\_get,实现动态属性访问;5.\_\_set,实现动态属性设置。这些方法在特定情况下自动调用,提升代码的灵活性和效率。

See all articles