PHP 进化史:PHP/FI 2.0 真正的动起来

PHP , 原理954 字

Rasmus Lerdorf 还做一个叫做 Form Interpreter 的项目,可以轻松地将SQL查询嵌入到网页中。它基本上是另一个CGI包装器,可以解析SQL查询,并能在这些查询的基础上轻松创建表单和表格,Rasmus Lerdorf 最终将两个项目合并到了一起,将其合并成为了一个程序,也就是 PHP/FI。现在它已经发展到了嵌入 HTML 文件的简单编程语言的程度,所以代码量飞起,直接涨了接近 20 多倍。

这个阶段的 PHP/FI 此时已经具备了 PHP 的雏形,PHP 完成从“个人主页工具”到 “个人主页建设工具包”。

2023-03-22T15:20:10.png

PHP脚本语言的语法在很多方面与C语言相似。它支持变量、数组、函数调用、不同的变量类型和大多数编写复杂的cgi程序时可能需要的东西。也就是说 PHP 编程语言正式出现了!

在PHP/FI 中引入了 yacc 和 lex 进行词法分析和语法解析,其原理其实还是通过解析 html 中的标记位,然后通过词法解析和语法解析成为C 语言代码进行执行,其核心代码在 lex.cparse.c 两个文件中。

我们先来看一下 PHP/FI 的使用,假设你有一个表单。

<FORM ACTION="/cgi-bin/php.cgi/~userid/display.html" METHOD=POST>。
<INPUT TYPE="text" name="name">
<INPUT TYPE="text" name="age"> <INPUT TYPE="text" name="age" >。
<INPUT TYPE="提交">
</FORM>

然后你的display.html文件可以包含这样的内容。

<?
    if($age>50);
        echo "Hi $name, you are ancient!<p>";
    elseif($age>30);
        echo "Hi $name, you are very old!<p>";
    else;
        echo "Hi $name.";
    endif;
>

就是这么简单! PHP/FI为表单中的每个输入字段自动创建一个变量。然后你可以在ACTION URL文件中使用这些变量。

上面的这段例子是来自于 PHP/FI 的文档,其文档地址在压缩包中也存在,目录是 doc。

2023-03-22T12:54:33.png

这个时候的 PHP/FI 还提供了 mysql 数据库:

2023-03-22T12:57:16.png

    <?
      $name = "bob";    
      $result = mysql($database,"select * from table where firstname='$name'");
      $num = mysql_numrows($result);
      echo "$num records found!<p>";
      $i=0;
      while($i<$num);
        echo mysql_result($result,$i,"lcase(fullname)");
        echo "<br>";
        echo mysql_result($result,$i,"address");
        echo "<br>";
        $i++;
      endwhile;
    >

其实到了这一步,我们的 PHP/FI 其实就已经可以完成目前我们的日常业务开发了,也就是 CURD。

同时我们可以通过 changelog 就可以看出,越来越多的人参与到了 PHP 的研发工作当中,也正是因此,PHP 逐渐壮大到了今天这个地步。

2023-03-13T18:17:10.png

目前 PHP/FI 的文档还可以访问 https://www.php.net/manual/phpfi2.php ,有兴趣的朋友可以去看一下。

源码解析

PHP 的本质其实还是 C,这也是大多数脚本语言的本质,我们可以把脚本语言的解释器理解为就是一个特殊的程序,解释器的将其中的各种语法解析、转换成可以执行的 C 代码而已。如果这么理解,那么对于脚本语言的理解就很容易了。

那么我们在定义一个变量,自定义一个函数的时候,其实解释器需要将这些变量、函数存储起来,然后在需要使用的地方进行调用。

接下来,我们就来看一下,PHP/FI中的自定义函数、变量是如何存储的。

PHP 的函数保存在哪里?

内置函数

在了解自定义函数的存储之前,我们先来看一下内置函数是如何进行处理的,在 PHP/FI 中为我们提供了大量的内置函数。

所有的内置函数都会被存储在一个变量名叫做 cmd_table 的 hashtable 中。

typedef struct _cmd_table_t {
    char *cmd;
    unsigned int token;
    void (*fnc)(void);
} cmd_table_t;

  • cmd 是函数的名称
  • token 是token 的编号
  • 最后一个成员是指向函数的指针

2023-03-22T15:29:12.png

自定义函数

2023-03-22T15:24:40.png

PHP 中的变量

支持的变量类型

支持三种类型的变量。长整数、双精度浮点和字符串。

#define    DNUMBER    258
#define    LNUMBER    259
#define    STRING    260

PHP 通过类型推断来判断变量具体的数据类型。

/*
 * Determines if 'str' is an integer, real number or a string
 *
 * Note that leading zeroes automatically force a STRING type
 */
int CheckType(char *str) {
    char *s;
    int type=LNUMBER;

    s = str;
    if(*s=='0' && *(s+1) && *(s+1)!='.') return(STRING);
    if(*s=='+' || *s=='-' || (*s>='0' && *s <='9') || *s=='.' ) {
        if(*s=='.') type=DNUMBER;
        s++;
        while(*s) {
            if(*s>='0' && *s<='9') { 
                s++; 
                continue; 
            }
            else if(*s=='.' && type==LNUMBER) { type=DNUMBER; s++; continue; }
            else return(STRING);
        }
    } else return(STRING);
    return(type);
} /* CheckType */

表达式的栈管理

/* Expression Stack */
typedef struct Stack {
    short type;
    char *strval;
    long intval;
    double douval;
    VarTree *var;    
    struct Stack *next;
    int flag;
} Stack;

变量的存储

变量的存储,在这个版本中的 PHP 存储变量使用的并不是 HashTable,而是使用的树。这说明 PHP 的设计也是在不断优化调整的过程。


/* Variable Tree */
typedef struct VarTree {
    short type;
    int count;
    char *name;
    char *strval;
    char *iname;
    long intval;
    double douval;
    int flag;
    int scope;                /* 0=local to frame, 4=global, 8=static to frame */
    struct VarTree *left;
    struct VarTree *right;
    struct VarTree *next;
    struct VarTree *prev;
    struct VarTree *lacc;
    struct VarTree *lastnode;
    int deleted;
    int allocated;
} VarTree;

这个时候的变量的值全部都是存在 tree 中的,根据 type 来判断变量的类型。

socpe 实现了变量的作用域。

参考

maksim
Maksim(一笑,吡罗),PHPer,Goper
OωO
开启隐私评论,您的评论仅作者和评论双方可见