Zend是什么?

Zend 是创造PHP的公司.

Zend引擎是一个开源脚本引擎 (一个虚拟机),因作为PHP语言的重要核心而闻名。它使用C语言编写,用来执行 PHP 脚本;

Zend是 PHP 的解释器,PHP的语法将由它来解析,同时 Zend 支持动态扩展,让 PHP 支持更多的功能;

PHP可以做什么?

PHP 作为一门语言什么都可以开发

  1. 服务器脚本 (90%,用来开发Web 应用)
  2. 命令行脚本 (如 nslookup 在 shell 中执行的命令行程序,PHP也可以开发,经常给运维人员使用,用的几率很少。一般使用Python)
  3. 图形界面(不是PHP的主攻方向,但是可以开发,需要加载扩展)

Zend 引擎支持动态扩展,只要有相应的扩展,连 Win32窗口程序都可以开发

扩展

image.png

在PHP安装目录的 ext 目录下,有着各种各样的扩展 dll (.so),在PHP配置文件中,可以配置 是否开启某个扩展,扩展开启后,PHP就有了这方面的能力;

如: 在PHP配置中开启 Mysql的扩展,则PHP就具有了连接MYSQL的能力;

其实,扩展的本质就是一些 C 函数库(dll/so),当Zend引擎解析PHP脚本的时候,遇到调用第三方扩展库的代码,则连接库,调用库里面的函数,从而完成某些PHP本身做不到的功能; 由于 Zend 引擎是C语言写的,所以要求扩展库可以被C所动态调用,接下来我们也会简单的了解到,如何 开发自己的扩展库~

所以,PHP理论上可以实现任何功能,只要有对应的扩展库~

查看当前PHP加载的扩展

扩展存放在 ext 目录下,需要在配置文件 php.ini 中开启后,才可以被加载 ;如何查看当前PHP环境,哪些扩展被加载那? 可以使用下面这几种办法

01、通过查看PHP的配置文件,看看开启了哪些扩展(不方便)

02、通过调用 php 命令获得扩展信息
在 PHP 的安装目录下,提供了一些 程序,这些程序就是用来运行PHP脚本的(如同 Java中的 java.exe)

image.png

php -m 列出开启的扩展(最清晰)
php -i 和 phpinfo() 效果一样,打印出PHP信息,从这里也能看出扩展,不过比较凌乱;
php -i > D:\out.txt 打印出 phpinfo() PHP信息,输出在 D:out.txt 里,内容重定向


03、 通过 php 代码 <? phpinfo() ?>; 来查看扩展,比较凌乱;

04、通过 PHP代码 $resultArr = get_loaded_extensions() 函数 来获得,返回一个 扩展名称 数组;

05、通过 PHP代码 extension_loaded("") 可以通过传入扩展名,检测扩展是否加载;

06、通过 PHP代码 function_exists("") 可以通过传入函数名,检测扩展中的函数是否存在,从而判断扩展是否加载;

查看扩展的信息(版本等)

php --ri 扩展名 指定某个扩展名,输出该扩展的信息,可以看到版本,也可以看到它是否被加载;

例如:

php --ri memcached

结果如下:

php --ri memcached

memcached

memcached support => enabled

Version => 2.2.0

自己开发扩展

一、使用ext-skel C语言开发

ext-skel是PHP官方源码里提供的生成php扩展的工具,可以生成一个c语言框架的php扩展的骨架。

PHP 官方对扩展开发者非常不友好,源代码中提供的Zend API极其难用,API复杂而且凌乱,充斥着各种宏的写法。Zend API坑非常多,普通开发者很容易踩到坑里。出现各种莫名其妙的core dump问题。Zend API几乎没有任何文档,开发者如果要真正掌握这项技能需要付出大量的学习时间。

以上是swoole扩展开发者的肺腑之言,可见用这个方法来开发扩展,对我们初学者来说将是对自信心极严重的打击。幸好有大神们为我们准备了其他开发php扩展的方法,不用学习zend api,不用精通c语言,也照样能开发php扩展,而且生成的扩展运行速度不会比c语言开发的相差太多。

二、使用zephir 类php语言开发

Zephir提供了一种类似php的高级语言语法的方式,来自动生成扩展的c语言代码,使编写php扩展变得非常的简单。不过这种开发方式带来了一个问题,就是由于他用的不是c/c++语言开发,那就没办法直接利用现有的各种c/c++开发库来实现强大的功能。所以感觉上有点鸡肋。

三、使用PHP-X C++语言开发

php-x是知名的swoole扩展开发者根据多年的开发经验,提炼出来的一套基于c++的扩展开发框架。从文档来看,这是一个比较容易上手的开发框架,数据类型很齐全,和php cpp的开发风格非常相似,但本人还没有去体验使用。
按照php-x官方的文档,开发出来的扩展只支持PHP7以上,这是一个遗憾。

四、使用phpcpp C++语言开发

PHP CPP是我重点推荐的php扩展开发框架,简明易懂,功能强大,开发效率高,代码易维护,执行速度快。

PHP CPP是一款免费的php开发扩展库,主要针对C++语言,可以进行类集合的扩展和构建,采用简单的计算机语言,让扩展变得更有趣更有用,方便开发者进行维护和编写,易于理解、维护轻松并且代码优美。用C ++编写的算法看起来与用PHP编写的算法几乎完全相同。如果你知道如何在PHP中编程,你可以很容易地学习如何在C ++中做同样的。

  • 优点一:不需要Zend引擎知识。

Zend引擎的内部太复杂,Zend引擎的代码是一团糟,并且大多是无证的。但是PHP-CPP库已经在非常容易使用的C ++类和对象中封装了所有这些复杂的结构。你可以使用C ++写出惊人的快速算法,而不必直接调用Zend引擎,甚至无需查看Zend引擎源代码。使用PHP-CPP,您可以编写本地代码,而无需处理PHP的内部。

  • 优点二:支持所有重要的PHP功能

使用PHP-CPP,您可以像使用普通PHP脚本一样轻松地处理变量,数组,函数,对象,类,接口,异常和命名空间。除此之外,你可以使用C ++的所有功能,包括线程,lambda和异步编程。

  • 优点三:支持PHP 5.X,PHP7的扩展开发

PHP-CPP有两套扩展开发框架,分别支持PHP 5.X,PHP7,虽然框架代码有两个,但是接口却是一样的。所以如果你要开发兼容多个版本的php扩展,不会花费你额外太多时间做兼容。

安装扩展就比较简单了,其实扩展就是函数库(动态连接库),将它放在 ext 目录下,并且在配置中开启加载即可;

(本文只做简单介绍,如果需要,查询更多资料来了解与开发

PHP两种执行方式

在 PHP 安装目录下,有 php.exe 和 php-cgi.exe,这两个都是执行PHP的解析器; php.exe 经常被用作 CLI命令行程序的 PHP解析器;
php-cgi.exe 被用作与Apache/Nginx配合的,FastCGI解析器;
所以 PHP 就有如下两种运行方式;

CLI 命令行执行

php D:\study.php

参数介绍:
php -a php采用shell交互式的方式运行PHP代码
php -c 使用指定路径的配置文件(或配置文件目录 )来运行PHP脚本

php index_cli.php -c D:\\apache\\apache2.2.22\\bin\\php.ini

php -i phpinfo信息输出
php -m 显示加载的模块
php -r 运行一段 PHP代码,而不是一整个脚本文件
php -v 版本号
php -h 帮助信息
php --ini 显示配置信息,采用的配置文件路径
php --ri 显示扩展名配置
php -S 执行的时候,顺便开启一个微型 Web Server方便调试,这个还是挺有用的,需要临时调一个PHP的时候,不用装Apache/nginx那么庞大的环境


php 命令行脚本获取命令行参数

1. 命令行自定义变量 【argv|argv|argc】
在命令行里输入程序参数来更改其运行方式是很常见的做法。你也可以对CLI程序这样做。 PHP CLI带有两个特殊的变量,专门用来达到这个目的:
  一个是$argv 变量,它通过命令行把传递给PHP脚本的参数保存为单独的数组元素;
  另一个是 $argc 变量,它用来保存$argv数组里元素的个数。

!!!要注意的是,$argv的第一个自变量总是脚本自己的名称。

php -f .\\cli.php name age sex

## cli.php代码
<?php
print_r($argv);

## 输出
array(4) {
  [0]=>
  string(9) ".\cli.php"
  [1]=>
  string(4) "name"
  [2]=>
  string(3) "age"
  [3]=>
  string(3) "sex"
}

2. 命令行自定义变量[Console getopt()]

注意:这个方式需要在配置中打开[register\_argc\_argv]

php.exe  \\tools\\index.php -f "value for f" -v -a --required value --optional="optional value" --option will

## tools\index.php 的代码
<?php
    $shortopts = "";
    $shortopts .= "f:";  // Required value
    $shortopts .= "v::"; // Optional value
    $shortopts .= "abc"; // These options do not accept values
    
    $longopts = array( "required:", // Required value
            "optional::", // Optional value
            "option", // No value
            "opt", // No value
    );
    $options = getopt($shortopts, $longopts);
    var_dump($options);
?>

结果:
array(6) {
  ["f"]=>
  string(11) "value for f" 
  ["v"]=>
  bool(false)
  ["a"]=>
  bool(false)
  ["required"]=>
  string(5) "value" 
  ["optional"]=>
  string(14) "optional value" 
  ["option"]=>
  bool(false)
}
CLI 命令行脚本的输入输出

在PHP CLI中,可以使用3个系统常量,分别为 STDIN、 STDOUT 和 STDERR。

(1) STDIN
     STDIN 全称为 standard in 或 standard input 标准输入可以从终端取得任何数据。

(2) STDOUT
     STDOUT 全称为 standard out 或 standard output 标准输出可以直接输出到屏幕(也可以输出到其他程序,使用STDIN取得),如果在PHP CLI模式里使用print或echo语句,则这些数据将发送到STDOUT。

(3) STDERR
     STDERR 全称为 standard error 在默认情况下会直接发送至用户终端,当使用STDIN文件句柄从其他应用程序没有读取到数据时会生成一个“stdin.stderr”。


<?php
/**
 * 本例是一个CLI与用户交互脚本,让其输出用户名与年龄并输出
 * 标准输出: fwrite(STDOUT,'请输出用户名:')    //输出内容
 * 标准输入: fgets(STDIN)                      //获取用户输入的内容
 * 标准错误输出: fwrite(STDERR,'错误:xxxxx')   //输出错误信息
 *
 * 运行效果:
 * [root@zzx tmp]# /usr/local/php/bin/php /wwwroot/test/httpsqs/cliPHP.php
 * Enter your name:
 * Enter your name:zhangsan
 * Enter your age:abc
 * Notice: age must be an integer,try again!
 * Enter your age:aaa  
 * Notice: age must be an integer,try again!
 * Enter your age:22
 * Hello zhangsan, your age is 22 
 */

$name = '';
$age  = '';
while(true){
    fwrite(STDOUT,"Enter your name:");  //标准输出,等待用户输入用户名
    $name = trim(fgets(STDIN));         //标准输入,立即获取用户名
    if(!empty($name)){
        break 1;
    }
}

while(true){
    fwrite(STDOUT,"Enter your age:");
    $age = trim(fgets(STDIN));
    if(empty($age)){
        continue 1;
    }
    $matchNum = preg_match('/^\d+$/',$age); //验证整型,获取匹配次数
    if($matchNum == 0){
        fwrite(STDERR,"Notice: age must be an integer,try again!\r\n");          
    }else{
        break 1;
    }
}

//do something here...
$outStr = "Hello $name, your age is $age";
fwrite(STDOUT,$outStr);
echo "\n\n";

?>

FastCGI(CGI) 方式执行

FastCgi的时候是使用 php-cgi 来解析PHP的,详情请直接 php-cgi -h 来看看如何使用它~

Web FastCGI 运行 和 CLI 运行时 不一致的问题

php.exe 和 php-cgi 虽然应用场景不同,但是他们背后都是同一个 Zend 引擎,但是有些时候,你会发现 Web PHP 的扩展 和 CLI 扩展不一致,这种情况可能出现,我们来分析一下原因;

比如,现在有一个 Web项目,你想看看当前加载了哪些扩展,你在Web 中使用 phpinfo() ,然后 php -m 也输出了当前加载的扩展列表,但是他们有可能不一致;

造成这样的原因是,有可能 php 和 php-cgi 分别加载了不同的 php.ini ; 如果想要 CLI 和 Web 的运行配置一致,那么可以使用命令,让CLI使用 Web 的配置;

# 让 index_cli.php 命令行脚本和 Web 使用相同的配置
php index_cli.php -c D:\\apache\\apache2.2.22\\bin\\php.ini

查看当前配置文件路径

php -i 和 phpinfo() 中有两个地方显示和当前配置相关的信息;

image.png

在 CLI 模式下,你可以使用 php --ini 来获得当前的配置文件位置


吴士岭
4 声望1 粉丝