PHP扩展开发利器之PHP-CPP库官方中文文档

看到此文,是否觉得体内洪荒之力爆发,饥渴难耐想吐槽、情不自禁想捐赠
本文为原创文章,尊重辛勤劳动,可以免费摘要、推荐或聚合,亦可完整转载,但完整转载需要标明原出处,违者必究。

支付宝微  信

如果对PHP-CPP感兴趣并期望看到中文版,拜托给Github的PHP-CPP-Document库点个赞,你的star我的动力。

这段时间对PHP扩展开发比较热衷,起初先趟了一遍(半遍吧)用Zend引擎来开发扩展的方式(http://www.walu.cc/phpbook/preface.md),可是问题来了。正如PHP官方所说的那样,”Zend的好处就是定义了很多宏,可惜坏处是宏真是太多了”。未知的东西是可怕的,也是困难的。所以相对比较起来,这个用纯C++的库来说(PHP-CPP),对于C++开发者真是轻车熟路。

翻译内容目前托管到了GitHub上,后续会陆续更新到本博,对PHP-CPP扩展感兴趣或者对于翻译感兴趣的朋友,请多指正~


目录

注:本博的内容旧于下文给出的Github内容,有兴趣的读者建议到Github总阅读。

PHP-CPP库有着丰富的文档。下面左侧的菜单中说明了如何在你的服务器中安装PHP-CPP和如何创建你的第一个扩展

其他文章

  • PHP如何加载扩展?
  • 输出(output)与错误(error
  • 注册原生函数
  • 函数参数
  • 调用函数
  • Lambda函数
  • 类与对象
  • 构造器与析构器
  • 类的继承
  • 魔术方法
  • 魔术接口
  • 特殊功能
  • 类的属性
  • 异常
  • 变量的使用
  • 全局常量与类常量
  • 加载php.ini文件
  • 扩展回调
  • 命名空间
  • 动态加载

通过GitHub反馈

该文档 - 实则是完整的库 - 正处于完善中。如果你发现了任何bug和错误,或者发现了有遗漏重要信息之处,请通过GitHub告知我们。


安装

在使用PHP-CPP来构建自己飞快的、原生的PHP扩展时,首先你不得不在系统上安装PHP-CPP库。

幸运的是,对于我们来说(那些使用Linux或者Apple环境的人),这就是小菜一碟。然而,如果你使用的是其他系统,那么你只能靠自己了(you are left on your own)。因为我们(指的是PHP-CPP的开发者),仅使用Linux系统。所以,这也没有任何理由来说明为什么这些库不应该运行在其他平台的言论,仅仅是因为它是由纯C++代码写的。因此,如果你在使用其他的系统,同时一直在设法编译它,那么请告知我们。我们来更新这些安装文档,并包含一些其他平台。

下载

安装的第一件事是下载源码。你既可以从我们的下载页面下载最新的发布版本,也可以从GitHub中下载最新的开发者版本(work-in-progress)。

为了获取最新的GitHub版本,运行如下行的命令:

$ git clone https://github.com/CopernicaMarketingSoftware/PHP-CPP.git

在你下载了软件之后(要么从我们的网站,要么直接从GitHub),改变当前的工作路径到PHP-CPP库的路径,然后用你熟悉的编辑器打开“Makefile”文件。查看全文>>


你的第一个扩展

当你创建自己的PHP-CPP扩展时,同样你不得不编译和部署它。一个正常的PHP脚本仅仅需要拷贝到Web服务上即可部署,但是部署一个扩展需要花费一些精力:你需要一个Makefile文件,一个用于扩展的php.ini文件,当然还有一个实现扩展业务的*.cpp文件。

为了让你清楚这些步骤,我们已经创建了一个几乎为空的扩展,但包含了所有这些必须的文件。它包含了一个Makefile文件,配置文件和一个已经实现get_module()调用的主函数文件main.cpp。这些会帮助你快速的开始扩展开发。

Makefile

上述的EmptyExtension文件中包含了一个详尽描述编译器的Makefile文件。为了满足你的扩展,你需要(简单地)修改下Makefile文件。其中最重要的修改地方就是扩展名称,也许还有INI_DIR配置。查看全文>>


PHP如何加载扩展

也许你知道,在类unix系统中,原生的PHP扩展需要编译成.so文件,而在Windows系统中,会编译成.dll文件,编译之后,全局php.ini文件会包含着系统中可用的扩展列表。也就是说,创建一个扩展并让PHP加载的话,需要生成一个.so或者.dll文件,然后更新PHP配置文件。

启动函数get_module()

在讲述如何创建你自己的扩展之前,我们先来看看PHP是如何加载扩展的。当PHP启动时,它会从配置目录下加载*.ini配置文件,并且读取配置文件中类似"extension=name.so"的每一行,相应地打开每一个库调用其中的"get_module()"方法。因此,每一个扩展(你的扩展也不例外)库都需要定义且实现”get_module()"函数。这个函数会在PHP加载扩展库后调用(and thus way before pageviews are handled),然后需要返回一个内存地址,指向着包含在扩展中有效编译的函数、类、变量和常量等信息构成的结构体。

get_module()函数返回的结构体类型已经在Zend引擎的头文件中定义过了,但它却没有很完善的文档,并且相当复杂。幸运的是,PHP-CPP会搞定这一切,因为它提供了一个可以替代这个结构体的Extension类。查看全文>>


输出与错误

你可以使用C++中常规的流类库,比如一些常规的操作符 << 和特殊的功能 std::endl。然而,并不推荐使用'std::out'和'std::err'。

当PHP以Web服务模块运行的时候,使用'std::out'的输出信息会直接输出到当初启动PHP的进程的终端中。在生产环境中,这种终端不是活跃状态的,所以任何以'std::out'发送出去的信息都会被丢掉。因此,在以Web模块方式运行的扩展中,使用'std::out'是无法进行的(no-go)。但是,尽管PHP将以命令行脚本(Cli script)的方式('std::out'可以正常使用),仍然不建议你直接使用'std::out'。使用'std::out'会被所有的已经在PHP用户脚本中定义的输出机制忽略(output handler)。

可以利用PHP-CPP库中提供的'Php::out' stream包来取而代之。这个'Php::out'变量就是众所周知的'std::ostream'类的一个实例,它会将所有的缓冲区中的输出内容指向PHP中。事实上,它和PHP中的echo函数的作用一样。

'Php::out'是'std::ostream'常规类的一个实例。这就说明了它使用了一个需要清理的内部缓冲区。当显示的写出'std::endl'或'std::flush'时,它会自动清空内部缓冲区。查看全文>>


增加原生函数

向PHP扩展中增加原生函数和(或者)类是非常有用的,且这些函数和(或者)类可以直接从PHP脚本中调用。对于函数来说非常简单。只要你按照下面的方式书写C++函数,那么你就可以直接从PHP脚本中调用它。

void example1();
void example2(Php::Parameters &params);
Php::Value example3();
Php::Value example4(Php::Parameters &params);

在上述的代码中有两个重要的PHP-CPP类,一个是Php::Value,一个是Php::Parameters。Php::Value类非常强大,它与PHP的变量作用一样:它可以容纳几乎任何值(整形、浮点型小数、字符串,当然也有索引和关联数组和对象)。Php::Parameters类以数组或向量的形式来接收传递到函数的所有变量是再适合不过了。后面我们会对这两个类进行深入的讨论。

为了能够在PHP中调用这些函数,那么你必须要将这些函数加入到extension对象中,同时赋予他们名称。将来在PHP脚本中将以这些名称来调用它们。查看全文>>


指定函数参数

在PHP中可以指定函数参数的类型与个数,并且可以返回一个引用类型或者值类型。在前面的例子中,我们还没有提到过这种机制。我们将这种机制设计到函数实现的环节中,通过检查函数参数'Php::Parameters'对象(它是一个装有Php::Value的std::vector),同时检查其参数的数量和类型是否正确。

所以,‘Extension.add()'方法提供了第三个可选参数。这个参数可以用来指定参数的数量,参数是用引用传递还是值传递和参数的类型:

#include <phpcpp.h>
void example(Php::Parameters &params)
{
}

extern "C" {
    PHPCPP_EXPORT void *get_module() {
        static Php::Extension myExtension("my_extension", "1.0");
        myExtension.add<example>("example", {
            Php::ByVal("a", Php::Type::Numeric),
            Php::ByVal("b", "ExampleClass"),
            Php::ByVal("c", "OtherClass")
        });
        return myExtension;
    }
}

正如上面你看到的,当我们注册'example'函数同时,通过了一些其他信息。我们告诉PHP引擎这个函数需要接收三个参数:第一个参数是整数,其它两个分别是‘ExampleClass'和'OtherClass'类的实例。最后,你的原生C++函数会接收到一个’Php::Parameters'的实例作为参数,但是当调用函数时,你可以确定Php::Parameters对象持有三个成员,其中有两个成员是上述类的相应实例。查看全文>>


调用PHP函数

首先,让我们先来明确一件事情。那就是,相对于运行PHP代码来说,运行原生代码是更快的。所以,一旦当你的C++函数或方法调用后,参数将转换成原生的变量,并且你将飞快地运行你自己的算法。同时,从那以后你将不愿意去调用其它PHP函数。

当然,如果你想调用PHP函数,无论这个函数已经定义在PHP引擎中,还是定义在扩展中,或者甚至是PHP应用层定义的函数,都是可以的。

从上面的例子中,你可以看出相对于PHP而言,利用C++在调用函数上会有所不同。第一个不同点就是调用Php::array_keys()函数。在PHP-CPP内部有着所有PHP重要函数的长列表,而且你可以直接从扩展中直接调用这些函数。Php::array_keys就是其中一个。

许多内置函数,比如Php::array_keys(),会返回Php::Value类的实例。然而,在这个例子中,你可以看出我们直接利用std::vector接收返回值。这是可以的,因为在PHP::Value类内部有着隐身转换运算符(implicit casting operator),她会自动地将这个对象转换成std::vector类型。查看全文>>


GitHub

https://github.com/GenialX/PHP-CPP-documentation


文章来源:胡旭个人博客 => PHP扩展开发利器之PHP-CPP库官方中文文档

转载请注明出处,违者必究!


这是一篇原创文章,如果您觉得有价值,可以通过捐赠来支持我的创作~
捐赠者会展示在博客的某个页面,钱将会用在有价值的地方,思考中...


分类: PHP, 技术, 编程, 翻译 | 标签: , , , , , , | 2个评论 | Permalink

2个评论

发表评论

电子邮件地址不会被公开。