V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gouchaoer
V2EX  ›  PHP

在 windows 下使用 zephir 写 php7 扩展

  •  1
     
  •   gouchaoer · 2016-12-28 18:12:10 +08:00 · 2116 次点击
    这是一个创建于 2905 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我博客原文: http://qsalg.com/?p=549

    著名的 php 框架 phalcon 为了更好的用 C 语言开发 php 扩展而发明了语言 zephir ,编译时 zephir 会被翻译成 C 语言然后编译成 php 扩展,我个人很喜欢这门语法朴素+规规矩矩+不装逼的语言。

    我平时在 windows 下工作,目前网上搜索到的在 windows 下用 zephir 写扩展的教程都已经过时了,我花了点时间打通了一下。我环境 windows 7 + VS2015 + php7.0 ,大体上按照官方文档来: https://github.com/phalcon/zephir/blob/master/WINDOWS.md ,我只把其中的一些需要注意的细节说一下。

    1 、去 http://windows.php.net/download/ 的 PHP 7.0 (7.0.14)的 zip 包,解压出来就是 php-7.0.14-nts-Win32-VC14-x86 文件夹,里面是编译好的 php 二进制。通过 setx path "%path%;c:\path-to-php"来把该目录加入环境变量,或者手动把该目录加入 path 环境变量,总之你的 path 环境变量中应该有类似这样的目录: F:\gouchaoer\cms\zephir\php-7.0.14-nts-Win32-VC14-x86

    2 、去 http://windows.php.net/downloads/php-sdk/ 下载 php-sdk-binary-tools-20110915.zip 这个包解压。通过 setx php_sdk "c:\path-to-php-sdk"来把该目录加入环境变量 php_sdk ,或者手动建立 php_sdk 环境变量并且把该目录加进去,注意不要自作聪明把该目录下的 bin 子目录加进去了( zephir 调用 sdk 的命令的时候是%php_sdk%\bin\balabala 这样来调用的),最后你的 php_sdk 环境变量类似: F:\gouchaoer\cms\zephir\php-sdk-binary-tools-20110915

    3 、下载 PHP Developer Pack(NTS!),也就是 http://windows.php.net/downloads/releases/ 里的 php-devel-pack-7.0.14-nts-Win32-VC14-x86.zip 这个包,解压里面还有一层目录 php-7.0.14-devel-VC14-x86 。通过 setx php_devpack "c:\path-to-extracted-devpack"加入环境变量,或者手动添加,最后你的 php_devpack 环境变量看起来类似: F:\gouchaoer\cms\zephir\php-devel-pack-7.0.14-nts-Win32-VC14-x86\php-7.0.14-devel-VC14-x86

    4 、 clone 或者下载 zephir 的 master 分支: https://github.com/phalcon/zephir ,我们看到 zephir 是 php 写的(目前 repo 的最新 tag 是 0.95 版本,我直接用的 master 分支,目前位于 75a6939 的 commit 上,如果你按照我的方法来走不通可以试试 checkout 到这个 commit 上)。然后把 zephir 源码目录下的 bin 子目录加入 path 环境变量: setx path "%path%;c:\path-to-zephir\bin",或者手动把该目录加入 path 环境变量,总之你的 path 环境变量中应该有类似这样的: F:\gouchaoer\cms\zephir\zephir\bin

    5 、打开开始菜单(如果你是 win8 我无能为力),在 visual stdio2015 下的 visual studio tools 下的 windows desktop command prompts 中找到"VS2015 x86 本机工具命令提示符",打开。执行 %PHP_SDK%\bin\phpsdk_setvars ,你会看到 REM phpsdk.bat 这样的回显

    OK ,环境配好了,来写个 zephir 的 hello world 吧, zephir 的语法请参考官方文档,给我们的扩展命名为 mitsuha 。

    "VS2015 x86 本机工具命令提示符"中进入一个空的工作目录下,这里我是 F:\gouchaoer\cms\zephir\gc 目录, zephir init mitsuha ,然后在 mitsuha 目录下生成了 ext 子目录、 mitsuha 子目录和 config.json 文件,在 mitsuha 子目录下,我们建立一个 taki.zep ,然后里面随便写点东西:

    namespace Mitsuha;
    class Taki
    {
    	public static function kataru()
    	{
    		echo "what's your name?";
    	}
    }
    

    然后回到"VS2015 x86 本机工具命令提示符"中,注意此时你的工作目录中有 config.json ,执行 zephir build 。如果 zephir 官方还没有处理这个 bug 的话,你会遇到这个问题:

    Preparing for parser compilation...
    Compiling the parser...
    
    Microsoft (R) Program Maintenance Utility Version 14.00.24210.0
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 14.0\VC\BI
    N\cl.exe"' : return code '0x2'
    Stop.
    
    Balabala
    

    问题见 issue : https://github.com/phalcon/zephir/issues/1366 ,官方并没有把文档适配到 php7 ,现在我们需要一点 hack 。如同那个 issue 中的办法,在 zephir 源码的目录找到 zephir\parser\parser\build_win32.bat ,把 php5 的地方改成 7 ,最后像这样:

    REM Build Lemon
    cl lemon.c
    del parser.c parser.h scanner.c
    re2c -o scanner.c scanner.re
    lemon -s parser.php7.lemon
    type parser.php7.c > parser.c
    type base.c >> parser.c
    

    完成再次尝试 zephir build 就可以成功的在 mitsuha\ext\Release 目录下看到 php_mitsuha.dll 扩展了。你上面下载的 php-7.0.14-nts-Win32-VC14-x86 这个 php 二进制里面没有默认 php.ini ,你需要自己建立一个 php.ini ,其中内容如下:

    extension_dir = "ext"
    extension=php_mitsuha.dll
    

    而 php_mitsuha.dll 复制到 F:\gouchaoer\cms\zephir\php-7.0.14-nts-Win32-VC14-x86\ext 目录下就可以了。(这里看出 windows 版本的 php 二进制是绿色版无依赖的,随便 copy 超级方便)

    然后 php -m 可以看到 mitusha 扩展已经加载了,然后写一个 keisei.php 内容为:

    <?php
    echo Mitsuha\Taki::kataru();
    

    然后 php keisei.php 就可以看到输出: what's your name?

    说起 zephir 就不得不啰嗦一下 phalcon , phalcon 框架和鸟哥的 yaf 框架一样,都是针对纯的 php 框架加载导致的性能损耗,采用了 C 语言来写框架从而让性能接近纯的单页 php 应用。 phalcon 和 yaf 最开始思路相同,而且性能是一样,参考鸟哥的压测: http://www.laruence.com/2012/09/16/2791.html 。而另一种思路则是类似 Swoole 和 phpdaemon 等 php-cli 常驻内存的异步方案(你可以理解成 php 版本的 nodejs ),然而这种方案 php-cli 本身就是一个 http 服务器(一些地方肯定没有 nginx/apache+php 方案那么成熟稳定,比如 https 支持之类的),而且常驻内存也会导致稳定性问题(和 nodejs 那样某个请求挂了应用就都挂了)没有 php-fpm 那么耐操,而且性能和 phalcon/yaf 一样: http://rango.swoole.com/archives/254 。因此除了需要 websocket 等异步功能情况下,我认为追求性能还是 yaf/phalcon 方案更好。而把 yaf 和 phalcon 这两个框架进行比较的话, phalcon 组件更丰富且社区更强大,我个人觉得 phalcon 的工作更漂亮。而后来 phalcon 把越来越多的组件用 C 扩展写,甚至还发明了 zephir 来缓解用 C 写 php 扩展的麻烦,让人眼睛一亮。

    其实我认为 yaf/zephir 提高性能的关键还是把框架用 C 扩展的方式,这样就大大减少了框架加载的时间使性能接近纯的单页 php 应用,至于用 C/zephir 把更多的 PHP 基础组件替换掉能否提高性能,还是个未知数: https://github.com/phalcon/zephir/issues/694 (可以看到 zephir 脸都被打肿了,当然了也有很多 benchmark 表示 zephir 的确提高了性能)。有部分同学认为 hello world 的压测无法反映真实的业务逻辑(尤其是 laravel 的用户就特别喜欢说瓶颈在数据库之类的),但是我认为恰恰相反,真实的业务逻辑恰恰是命中缓存的情况最多,降低 cpu 消耗的同时减小处理时间是很诱人的。而 zephir 的另一个很大的用处我认为就是简化了我们开发 C 扩展的难度,你知道扩展里一堆宏一堆 zend api 让人很烦,而大多数情况下我只是想集中精力写逻辑业务而已。如果你想对 php 代码加密 /限制授权,代码混淆和商用加密方案都不算完美,用 zephir 直接把关键代码编译成扩展可以说是雪中送炭。而且 zephir 还提供了 Optimizer (官方比较推荐这种方式)和 CBlock 两种方式来让我们嵌入 C 代码,也提供了机制来添加别的第三方库依赖。前面说过我很喜欢 zephir 的朴素使用的语法,如果真的要说哪点不喜欢的话,那就是它的内建的几个面向对象的方法: https://docs.zephir-lang.com/en/latest/builtin-methods.html ,我认为 zephir 的 string 和 array 性质应该尽可能的像 php ,这几个方法最后还是会编译成面向过程的 php 的方法,本质上是就是语法糖。

    1 条回复    2016-12-28 19:44:26 +08:00
    sagaxu
        1
    sagaxu  
       2016-12-28 19:44:26 +08:00
    跟 cython 一个类型
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5009 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 08:03 · PVG 16:03 · LAX 00:03 · JFK 03:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.