拓展篇——Zephir快速入门

如果你想自己编写PHP扩展,意味着你需要掌握C语言,因为PHP的扩展是通过C编写的,而且你还需要掌握PHP的Zend API,了解它的核心原理

但是最近了解到一个新的技术:Zephir

它可以帮助你使用类PHP的语法,来生成C语言代码,并帮助你编译成PHP扩展。是不是很酷?很酷,有没有?

根据 Zephir 的作者(出是phalcon的核心成员)的描述:Zephir是一门能使用语法与PHP相同且纯面向对象的编译型语言。它将代码编译为C语言,再生成PHP扩展。

Zephir 有几个特性:

  • 类型可静可动。即支持PHP类似的动态类型、也可以支持类似C语言的静态类型。
  • 减少程序执行时间提升运行性能。毕竟是把代码编译为静态类型的C语言。
  • 采用面向对象OOP编译。
  • 内存安全。即不需要操心内存的管理问题。
  • 预编译器(AOT)提供可预测的性能。

Zephir是开放源代码的项目。代码托管在github:https://github.com/phalcon/zephir

任何语言都有数据类型。Zephir与PHP和C的数据类型高度相关。

类型

Zephir 支持动态和静态两种类型。在这一章里,我们强调支持的类型和它的行为:

动态类型

与PHP动态变量是完全一样的,它们可以被分配和重新分配不同类型且没有限制。一个动态变量必须用关键字“var”声明,和PHP中的行为几乎是一样的:

1
2
3
4
5
6
7
8
9
10
var a, b, c;

// Initialize variables
let a = "hello", b = false;

// Change their values
let a = 10, b = "140";

// Perform operations between them
let c = a + b;

他们总共有八个数据类型:

类型 描述
boolean 布尔值。 true or false.
integer 整数的数字。整数的大小是与平台相关的。
float/double 浮点数。浮动的大小是与平台相关的。
string 一串字符组成的字符串。每个字符一个字节。
array 数组是有序的。
object 对象。与PHP对象一致。
resource 与PHP一致
null 与PHP一致

本节要点:

  • 代码文件组织结构。
  • 命名空间。
  • 语法习惯。
  • 其他概念。

代码文件组织结构与命名空间

在PHP中,我们可以将代码放到任何文件中。且代码不局限于特定的形式。在Zephir中,每个文件必须包含一个类且只能有一个类。每个类必须有一个命名空间和目录结构相同。

例如,以下就是一个标准的Zephir组织结构:   

1
2
3
4
mylibrary/
router/
exception.zep # MyLibrary\Router\Exception
router.zep # MyLibrary\Router

MyLibrary\Router 类对应的代码如下:

1
2
3
4
5
6
namespace MyLibrary;

class Router
{

}

类MyLibrary/Router/Exception代码如下:

1
2
3
4
5
6
namespace MyLibrary\Router;

class Exception extends \Exception
{

}

语句分隔

不同语句表达式之间使用分号进行分隔。跟PHP、C/C++、Java一样。例:

1
myObject->myMethod(1, 2, 3); echo "world";

注释

Zephir 支持 C/C++ 风格的注释。如:

1
2
3
4
5
// this is one line comment

/**
* multi-line comment
*/

在大多数语言中,注释会被编译器/解释器忽略。在 Zephir 中,注释会当作文档并输出到生成的代码中去。所以,它是代码的一部分。

变量声明

Zephir,所有的变量在使用前都必须进行声明。编译器会根据提供的重要信息进行优化和验证。变量必须是惟一的标识符,他们不能是保留字。

1
2
3
4
5
6
7
// 在同一行代码中定义多个变量。
var a, b, c;

// 在不同行中定义变量。
var a;
var b;
var c;

定义变量的时候,可以给变量一个默认值。您可以为变量设置一个您想要的值。

1
2
3
//Declaring variables with default values
var a = "hello", b = 0, c = 1.0;
int d = 50; bool some = true;

变量名是区分大小写的,下面的变量是不同的:

1
2
// Different variables
var somevalue, someValue, SomeValue;

变量作用域

在方法中定义的变量的作用域都是局部的。例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace Test;

class MyClass
{

public function someMethod1()
{
int a = 1, b = 2;
return a + b;
}

public function someMethod2()
{
int a = 3, b = 4;
return a + b;
}

}

超全局变量

Zephir 不支持全局变量, 访问PHP中的全局变量是不允许的。然而,您可以访问PHP的超全局变量如下:

1
2
3
4
5
// 从 PHP 的 $_POST 中读取一个值。
let price = _POST["price"];

// 从 PHP 的 $_SERVER 中读取一个值。
let requestMethod = _SERVER["REQUEST_METHOD"];

译注:在 Zephie的变量是没有PHP的$符号的。所以,就算要调用$_POST或$_SERVER等变量的时候,也不允许有$符号。

本地符号表(Local Symbol Table)

在PHP中,每个变量都当前的上下文中都有一个对应的符号表。所以,可以动态地调用或向里面写入值。(对应的PHP术语叫:可变变量)。

1
2
3
4
5
<?php

$b = 100;
$a = "b";
echo $$a; // prints 100

Zephir没有实现这一功能,因为所有变量都被编译到低级变量,没有办法知道哪些变量存在于一个特定的上下文。如果你想创建一个变量在当前的PHP符号表,您可以使用下面的语法:

1
2
3
4
5
6
//Set variable $name in PHP
let {"name"} = "hello";

//Set variable $price in PHP
let name = "price";
let {name} = 10.2;

Zephir 依赖以下库:

环境要求:

  • g++ >= 4.4/clang++ >= 3.x/vc++ 9
  • gnu make 3.81 or later
  • php development headers and tools

一、安装

1)安装依赖re2c:

因为,我的是Mac系统,所以。我使用的是如下命令安装:

1
brew install re2c

如果你的是centos,那么应该使用如下命令安装:

1
yum install re2c

2)安装Zephir

创建一个文件夹 zephir_test(名字随意),然后,我们使用composer安装:

1
2
3
4
5
6
$ composer require phalcon/zephir
$ cd ./zephir_test/vendor/phalcon/zephir
$ git clone https://github.com/json-c/json-c.git
$ ./install-json
$ ./install -c
$ ./zephir_test/vendor/phalcon/zephir/bin/zephir compile

通过以上步骤就算安装好了。测试安装是否成功:

1
2
$ cd ./zephir_test/vendor/phalcon/zephir/bin
$ ./zephir

如果没有报错,说明就安装成功了。

3)将 zephir 命令添加到 PATH中

1
$ vim /etc/profile

在文件末尾增加如下代码:

1
export PATH=$PATH:/Users/qlj/codespace/phpcode/zephir_test/vendor/phalcon/zephir/bin

激活使其生效:

1
$ source /etc/profile

二、创建第一个Zephir扩展

通过 Zephir 命令创建:

1
2
3
$ zephir init wlib
$ cd wlib/wlib
$ vim greeting.zep

增加如下代码:

1
2
3
4
5
6
7
8
9
namespace Wlib;

class Greeting
{
public static function say()
{
echo "hello world!";
}
}

greeting.zep路径为wlib/wlib/greeting.zep。

则需要在greeting.zep上一级目录下执行如下命令编译:

1
$ zephir build

输入如下内容则编译成功:

1
2
3
4
5
Compiling...
Installing...
Password:
Extension installed!
Don't forget to restart your web server

这个时候,就已经生成了so文件。则只需要在php.ini末尾增加如下内容:

1
2
[wlib]
extension=wlib.so

测试代码:

1
$ vim test.php

增加如下代码:

1
2
<?php
echo Wlib\Greeting::say(), "\n";

执行输出如下内容:

1
$ php test.php

输出:

1
hello world!
坚持原创技术分享,您的支持将鼓励我继续创作!