목차
前言" >前言
跟踪运行轨迹" >跟踪运行轨迹
词法语法分析->opcode" >词法语法分析->opcode
虚拟机执行opcode" >虚拟机执行opcode
结语" >结语
백엔드 개발 PHP 튜토리얼 PHP-Zend发动机剖析之Hello World(二)

PHP-Zend发动机剖析之Hello World(二)

Jun 13, 2016 pm 12:32 PM
echo handler zend

PHP-Zend引擎剖析之Hello World(二)

前言

这一次,我围绕Hello World来展开Zend虚拟机的执行过程。Hello World的PHP版本:


? ? ?echo 'Hello World';

?>


前一篇文章聊到的词法分析阶段就会把上边的脚本分析出一个Token序列:

我们得到一个Token序列:T_OPEN_TAG, T_ECHO, T_CONSTANT_ENCAPSED_STRING, ';', T_CLOSE_TAG。但在Zend虚拟机执行的过程中,是怎么去分析这个Token序列的?

跟踪运行轨迹

我们还是从命令行入手,在$PHPSRC/sapi/cli/php_cli.c中的do_cli函数里边接收了命令行的参数输入(php -f HelloWorld.php表示执行HelloWorld.php文件)。

我们追踪到$PHPSRC/main/main.c里边有php_execute_script的定义,紧接着调用了zend_execute_scripts() ,在zend_execute_scripts的定义里边我们发现了:


?EG(active_op_array) =?zend_compile_file(file_handle, type TSRMLS_CC); zend_execute(EG(active_op_array) TSRMLS_CC);


首先通过zend_compile_file把文件解析成opcode中间代码(这一步会经过词法语法分析),然后用zend_execute执行这个生成的中间代码(这里就是所谓的运行时)。

这里很像C语言的编译方式,先编译成汇编,然后再转成机器码,这里的opcode就类似C语言编译过程中生成的汇编。

还可以延伸出一个思路,因为每次解析PHP文件时,都需要经过词法语法分析得到对应的opcode,其实在脚本文件不变化的时候,生成的opcode也不需要变化,因此为了减少PHP脚本的执行时间,可以把脚本的opcode缓存起来(例如缓存在共享内存里边)。

我给出一个流程图,然后随着这个流程图,看看Zend做了些什么事情:

我们先看看如何编译出opcode的。

词法语法分析->opcode

从上节知道我们通过zend_compile_file(实际上为compile_file())把脚本文件编译出opcode,实际上通过zendparse这个API来编译出opcode的。
PHP的语法解析器是用bison来生成,安装完之后在$PHPSRC/Zend目录运行:
bison -o zend_language_parser.c?zend_language_parser.y
在Zend目录下就会生成语法解析器zend_language_parser.c。而这里的zendparse就是语法解析器里边的yyparse!
我们忽略掉生成的语法解析器,就Hello World的例子来跟踪一下bison的声明文件(我去掉不想关的声明):

start:
top_statement_list???? { zend_do_end_compilation(TSRMLS_C); }
;top_statement_list:
top_statement_list? { zend_do_extended_info(TSRMLS_C); } top_statement { HANDLE_INTERACTIVE(); }
|???? /* empty */
;top_statement:
statement????????????????????????????? { zend_verify_namespace(TSRMLS_C); }
;statement:
unticked_statement { DO_TICKS(); }
|???? T_STRING ':' { zend_do_label(&$1 TSRMLS_CC); }
;unticked_statement:
|???? T_ECHO echo_expr_list ';'echo_expr_list:
echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
|???? expr???????????????????????? { zend_do_echo(&$1 TSRMLS_CC); }
;

expr:
r_variable???????????????????????? { $$ = $1; }
|???? expr_without_variable????????? { $$ = $1; }
;

expr_without_variable:
|???? scalar??????????????????? { $$ = $1; }

scalar:
|???? common_scalar?????????????? { $$ = $1; }
;

common_scalar:
|???? T_CONSTANT_ENCAPSED_STRING???? { $$ = $1; }
;
로그인 후 복사

语法分析从start开始,自上而下的分析,一个PHP脚本就是对应一个top_statement_list,接着分成每一行一条语句statement,发现echo 'Hello World'是一条unticked_statement(留意一下echo_expr_list的声明,?我们还可以发现语法上是支持echo 'Hello', ' World'的)。最后递归到T_CONSTANT_ENCAPSED_STRING状态就结束了这一行的语法解析。在这里我们忽略掉编译原理在语法分析阶段是怎么去做回溯等等东西,我们关注一下Zend引擎自身的的问题。

在规则后边的块"{}"里边的代码就是用来处理扫描到此规则时的动作,可以看到echo的执行是调用了zend_do_echo函数的。在动作声明的块里边我们看到了$$, $1,$2,$3等,这些对应的就是该条规则里边的返回值,参数1,参数2……,这里的返回值以及参数都是YYSTYPE类型,这个类型在43行里边有定义:#define YYSTYPE znode。znode的定义在zend_compile.h里边:

留意到zend_op这个结构,于是跟踪发现这个就是最后每条语句对应的opcode结构了!!!!

opcode的结构跟汇编有很大的相似之处,一个操作符,两个操作数。

在Zend引擎中,每个opcode主要的东西就是那个handler,一会我们会看到Zend里边是怎么生成这个handler的。到了这里先Hold住一下,回过头,我们看一下Hello World这个例子生成的opcode是什么。

装上vld,然后运行:php -dvld.active=1 HelloWorld.php,我们就可以看到这个PHP文件编译出来的opcode列表了:

可以看到echo这个语句的opcode类型是ECHO,同时return没有返回值,只有一个操作数"Hello World"。

现在经过了语法分析,我们对每条语句都编译出了opcode,Zend就会把它放入一个op_array里边(其实就是一个opcode的列表)。

回过头我们看一下zend_do_echo做了什么事情:

首先通过get_next_op在当前的op_array的最后边生成一条opcode,然后设置其opcode类型是ZEND_ECHO,然后设置它的第一个参数op1,同时标记第二个参数op2是不需要使用的(unused的)。

经过了这么多步骤之后我们得到了一个op_array的列表,这个列表里边的每一条opcode都绑定了自己的类型,接着我们看一下每个opcode节点是如何绑定handler的。

zend_vm_def.h定义了ZEND_ECHO的handler,留意到这里的40,一会需要用到,因为echo的参数可以有几种:常量,变量等等,所以对应着不同的handler

在zend_vm_execute.h定义了opcode对应的所有的handler,我们只关注echo相关的handler,注意到其中的代码:


void zend_init_opcodes_handlers(void) { static const opcode_handler_t labels[] = {//40913行 ZEND_ECHO_SPEC_CONST_HANDLER,//41914行 ZEND_ECHO_SPEC_CONST_HANDLER, ZEND_ECHO_SPEC_CONST_HANDLER, ZEND_ECHO_SPEC_CONST_HANDLER, ZEND_ECHO_SPEC_CONST_HANDLER };


请花费短暂的时间先记住这里的labels以及行数。

发现了获取handler的方法最后边return语句的计算,根据前面说的echo的opcode是40(假设两个参数op1,op2的type都是0),于是乎其对应的handler就是:

zend_opcode_handlers[40*25+0*5+0*5] =?zend_opcode_handlers[1000] =?labels[1000] =?ZEND_ECHO_SPEC_CONST_HANDLER(怎么来的?因为:41914行-40913行-1=1000)。

虚拟机执行opcode

前边我们已经解释了zend_compile_file把一个脚本编译成一个opcode的list:


?EG(active_op_array) =?zend_compile_file(file_handle, type TSRMLS_CC); zend_execute(EG(active_op_array) TSRMLS_CC);


在这之后,Zend引擎用zend_execute执行返回的opcode。

我们定位到了zend_execute最后执行到Zend/zend_vm_execute.h的337行:

可以看到,虚拟机执行的时候会循环当前的opcode列表,然后调用每一行opcode的handler,根据handler返回值确定下一步做啥(例如函数调用等,以后再展开)。

在这篇文章中我们只关注跟Hello World相关的东西,我们前边知道echo的handler是ZEND_ECHO_SPEC_CONST_HANDLER,通过最后的定位你会发现其调用了:


zend_write = (zend_write_func_t) utility_functions->write_function;


这里的utility_functions里边包含了一些基础的handler,每个sapi接入层自己修改了这里的基础函数指针,例如在命令行模式下,最后调用到了

sapi_cli_single_write:

从源码中,我们看到了最后的写操作就是调用了write/fwrite写入到标准输出流(也即是终端屏幕上)。

结语

最后根据前边的过程,再展开一下流程图就是:

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

기술 세계를 탐험할 수 있도록 Go 언어 오픈 소스 프로젝트 5개를 선택했습니다. 기술 세계를 탐험할 수 있도록 Go 언어 오픈 소스 프로젝트 5개를 선택했습니다. Jan 30, 2024 am 09:08 AM

오늘날 급속한 기술 발전의 시대에 프로그래밍 언어는 비가 내린 뒤 버섯처럼 솟아오르고 있습니다. 많은 주목을 받고 있는 언어 중 하나가 바로 Go 언어인데, 단순성, 효율성, 동시성 안전성 등 다양한 기능으로 많은 개발자들에게 사랑을 받고 있습니다. Go 언어는 뛰어난 오픈 소스 프로젝트가 많이 포함된 강력한 생태계로 유명합니다. 이 기사에서는 선택된 Go 언어 오픈 소스 프로젝트 5개를 소개하고 독자가 Go 언어 오픈 소스 프로젝트의 세계를 탐색하도록 안내합니다. KubernetesKubernetes는 자동화를 위한 오픈 소스 컨테이너 오케스트레이션 엔진입니다.

Go 언어 개발 필수 사항: 인기 있는 프레임워크 권장 사항 5가지 Go 언어 개발 필수 사항: 인기 있는 프레임워크 권장 사항 5가지 Mar 24, 2024 pm 01:15 PM

"Go 언어 개발 필수 사항: 5가지 인기 프레임워크 권장 사항" 빠르고 효율적인 프로그래밍 언어인 Go 언어는 점점 더 많은 개발자들이 선호하고 있습니다. 개발 효율성을 높이고 코드 구조를 최적화하기 위해 많은 개발자는 프레임워크를 사용하여 애플리케이션을 빠르게 구축하는 방법을 선택합니다. Go 언어의 세계에는 선택할 수 있는 훌륭한 프레임워크가 많이 있습니다. 이 기사에서는 인기 있는 Go 언어 프레임워크 5개를 소개하고 독자가 이러한 프레임워크를 더 잘 이해하고 사용할 수 있도록 구체적인 코드 예제를 제공합니다. 1.GinGin은 빠른 속도를 갖춘 경량 웹 프레임워크입니다.

Zend Framework에서 권한 제어를 위해 ACL(Access Control List)을 사용하는 방법 Zend Framework에서 권한 제어를 위해 ACL(Access Control List)을 사용하는 방법 Jul 29, 2023 am 09:24 AM

Zend Framework에서 권한 제어를 위해 ACL(AccessControlList)을 사용하는 방법 소개: 웹 애플리케이션에서 권한 제어는 중요한 기능입니다. 이는 사용자가 액세스 권한이 있는 페이지와 기능에만 액세스할 수 있도록 하고 무단 액세스를 방지합니다. Zend 프레임워크는 ACL(AccessControlList) 구성 요소를 사용하여 권한 제어를 구현하는 편리한 방법을 제공합니다. 이 기사에서는 Zend Framework에서 ACL을 사용하는 방법을 소개합니다.

Golang의 웹 프레임워크인 Echo 프레임워크를 사용하여 분산 작업 스케줄링 구현 Golang의 웹 프레임워크인 Echo 프레임워크를 사용하여 분산 작업 스케줄링 구현 Jun 24, 2023 am 11:49 AM

인터넷의 발달과 정보기술의 발달로 빅데이터 시대가 도래하면서 데이터 분석, 머신러닝 등의 분야도 널리 활용되고 있다. 이러한 분야에서 작업 스케줄링은 피할 수 없는 문제입니다. 효율적인 작업 스케줄링을 달성하는 방법은 효율성을 향상시키는 데 중요합니다. 이 글에서는 Golang의 웹 프레임워크인 Echo 프레임워크를 사용하여 분산 작업 스케줄링을 구현하는 방법을 소개합니다. 1. Echo 프레임워크 소개 Echo는 확장성이 뛰어나고 가벼운 고성능 GoWeb 프레임워크입니다. HTTP를 기반으로 합니다.

PHP 구현 프레임워크: Zend 프레임워크 시작 튜토리얼 PHP 구현 프레임워크: Zend 프레임워크 시작 튜토리얼 Jun 19, 2023 am 08:09 AM

PHP 구현 프레임워크: ZendFramework 입문 튜토리얼 ZendFramework는 PHP에서 개발하고 현재 ZendTechnologies에서 유지 관리하는 오픈 소스 웹 사이트 프레임워크입니다. ZendFramework는 MVC 디자인 패턴을 채택하고 Web2.0 애플리케이션 및 Web Serve 구현을 지원하기 위한 재사용 가능한 코드 라이브러리 시리즈를 제공합니다. ZendFramework는 PHP 개발자들에게 매우 인기 있고 존경받고 있으며 다양한 기능을 갖추고 있습니다.

Laravel 개발: Laravel Echo 및 Pusher를 사용하여 WebSocket 통신을 구현하는 방법은 무엇입니까? Laravel 개발: Laravel Echo 및 Pusher를 사용하여 WebSocket 통신을 구현하는 방법은 무엇입니까? Jun 13, 2023 pm 05:01 PM

Laravel은 확장성이 뛰어나고 효율적인 인기 있는 PHP 프레임워크로 개발자가 고품질 웹 애플리케이션을 신속하게 구축할 수 있는 많은 강력한 도구와 라이브러리를 제공합니다. 그중 LaravelEcho와 Pusher는 WebSocket 통신을 쉽게 구현할 수 있는 두 가지 매우 중요한 도구입니다. 이 기사에서는 Laravel 애플리케이션에서 이 두 도구를 사용하는 방법을 자세히 설명합니다. WebSocket이란 무엇입니까? 웹소켓

PHP에서 echo 키워드의 역할과 사용법에 대한 자세한 설명 PHP에서 echo 키워드의 역할과 사용법에 대한 자세한 설명 Jun 28, 2023 pm 08:12 PM

PHP에서 echo 키워드의 역할과 사용법에 대한 자세한 설명 PHP는 널리 사용되는 서버측 스크립트 언어로 웹 개발에 널리 사용됩니다. echo 키워드는 PHP에서 내용을 출력하는 데 사용되는 메서드입니다. 이번 글에서는 echo 키워드의 기능과 사용법을 자세히 소개하겠습니다. 기능: echo 키워드의 주요 기능은 콘텐츠를 브라우저에 출력하는 것입니다. 웹 개발에서는 데이터를 프런트엔드 페이지에 동적으로 표시해야 합니다. 이때 echo 키워드를 사용하여 데이터를 페이지에 출력할 수 있습니다. 이자형

Go 언어 프레임워크 살펴보기: 놓칠 수 없는 5가지 선택! Go 언어 프레임워크 살펴보기: 놓칠 수 없는 5가지 선택! Feb 19, 2024 pm 02:29 PM

빠르고 효율적인 프로그래밍 언어인 Go 언어는 항상 프로그래머들이 선호해 왔습니다. Go 언어 생태계에서 프레임워크는 개발자가 애플리케이션을 더 빠르게 구축하는 데 중요한 역할을 합니다. 이 글에서는 다섯 가지 Go 언어 프레임워크를 소개하여 해당 프레임워크의 특징과 사용법을 이해할 수 있도록 하겠습니다. 1. Gin 프레임워크 Gin 프레임워크는 빠르고 고성능 특성을 갖춘 경량 웹 프레임워크입니다. Gin 프레임워크를 사용하여 RESTful API 및 웹 애플리케이션을 빠르게 구축하세요. 다음은 간단한 예제 코드입니다:

See all articles