maksim 发布的文章

PHP4.0整个脚本程序的核心大幅更动,让程序的执行速度,满足更快的要求。在最佳化之后的效率,已较传统CGI或者ASP等程序有更好的表现。而且还有更强的新功能、更丰富的函数库。无论您接不接受,PHP 都将在 Web CGI 的领域上,掀起巅覆性的革命。对于一位专业的Web Master 而言,它将也是必修课程之一。

PHP4.0这些优异的性能是PHP 脚本引擎重新设计产生的结果:引擎由 AndiGutmans 和 Zeev Suraski从底层全面重写。PHP4.0 脚本引擎 ——Zend 引擎,使用了一种更有效的编译——执行方式,而不是PHP 3.0 采用的执行 ——当解析时模型。

在 PHP4.0 版本,用 cloc 统计代码如下。

2023-03-24T04:24:32.png

这个时候的代码量已经接近 20W 行。

上面也提到了PHP4.0 最大的变化 Zend 引擎。

PHP执行这段代码会经过如下4个步骤(确切的来说,应该是PHP的语言引擎Zend)

  1. Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)
  2. Parsing, 将Tokens转换成简单而有意义的表达式
  3. Compilation, 将表达式编译成Opocdes
  4. Execution, 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。

1997年中PHP的发展也已经有了一些变化,他已经从Rasmus的宠物项目变成了更加有组织的团体项目。语法分析引擎也由Zeev Suraski 和 Andi Gutmans进行了重新改写,这个引擎构成了PHP3的基础。PHP/FI中的大部分通用代码都经过改写后引入了PHP3中。

目录结构上,PHP 越来越工程化。

  • serverapi: 抽离出了 PHPSAPIs。
  • win32:支持了 Windows
  • VarTree 被替换成了大名鼎鼎的 HashTable,到现在直接变成了恶臭的 PHP 八股文必考内容。
  • convertor 将 PHP/FI 的代码转换为 PHP3 代码的工具,其核心原理是 yacc 和 lex。
  • DL:扩展,在 php3 中开始支持扩展啦!

变量

hashtable 出现了,代替了原来的 VarTree

typedef struct hashtable {
    uint nTableSize;
    uint nHashSizeIndex;
    uint nNumOfElements;
    uint nNextFreeElement;
    uint(*pHashFunction) (char *arKey, uint nKeyLength);
    Bucket *pInternalPointer;    /* Used for element traversal */
    Bucket *pListHead;
    Bucket *pListTail;
    Bucket **arBuckets;
    void (*pDestructor) (void *pData);
    unsigned char persistent;
} HashTable;

在 PHP 中 HashTable 中非常重要,在 PHP/FI 中函数被保存在一个链表中,但是链表的时间复杂度是 O(N),在 PHP3 中,由于出现了 HashTable,其查询时间复杂度是 O(1),这样用 HashTable 代替链表存储函数也就成了必然。

PHPAPI int _php3_hash_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag)

最近一直再看 PHP 的底层源码,同时也对如何开发一门语言来了兴趣,看了《自制编程语言》这本书,在第一个计算机的例子上就栽了跟头。

按照书上的例子写完代码后报错:

y.tab.c:1049:16: error: implicit declaration of function 'yylex' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
      yychar = yylex ();
               ^
y.tab.c:1224:7: error: implicit declaration of function 'yyerror' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
      yyerror (YY_("syntax error"));
      ^
y.tab.c:1335:3: error: implicit declaration of function 'yyerror' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  yyerror (YY_("memory exhausted"));
  ^

最终 google 了一番发现很多人卡在这里。

https://stackoverflow.com/questions/20106574/simple-yacc-grammars-give-an-error

最终找到了这个提问解决了这个问题,其实主要是找不到定义文件,我们在定义 yacc 文件的时候,需要在头部定义一下。

%{
#include <stdio.h>
#include <stdlib.h>
#define YYDEBUG 1
int yylex(void);
int yyerror(char const *str);
%}