php自定义函数调用和执行过程详解
函数被调用需要一些基本的信息,比如函数的名称,参数以及函数的定义(也就是函数的具体执行内容), 从我们开发者的角度来看,定义了一个函数我们在执行的时候自然知道这个函数叫什么名字, 以及调用的时候给传递了什么参数、函数的操作内容。但是对于Zend引擎不能像我们这样能“看懂”php源代码, 它需要对代码进行处理以后才能执行。我们还是从以下两个小例子开始:
<?php function foo(){ echo "I'm foo!"; } foo(); ?>
下面我们先看一下其对应的opcodes:
function name: (null)line # * op fetch ext return operands
---------------------------------------------------------------------------------
DO_FCALL 0 'foo'
NOP
> RETURN 1
function name: foo
line # * op fetch ext return operands
---------------------------------------------------------------------------------
4 0 > ECHO 'I%27m+foo%21'
5 1 > RETURN null
上面是去除了一些枝节信息的的opcodes,可以看到执行时函数部分的opcodes是单独独立出来的,这点对于函数的执行特别重要,下面的部分会详细介绍。 现在,我们把焦点放到对foo函数的调用上面。调用foo的OPCODE是“DO_FCALL“, DO_FCALL进行函数调用操作时,ZE会在function_table中根据函数名 (如前所述,这里的函数名经过str_tolower的处理,所以PHP的函数名大小写不敏感)查找函数的定义, 如果不存在, 则报出“Call to undefined function xxx()"的错误信息; 如果存在,就返回该函数zend_function结构指针, 然后通过function.type的值来判断函数是内部函数还是用户定义的函数, 调用zend_execute_internal(zend_internal_function.handler)或者直接 调用zend_execute来执行这个函数包含的zend_op_array。
函数的执行
细心的读者可能会注意到上面opcodes里函数被调用的时候以及函数定义那都有个"function name:",其实用户定义函数的执行与其他语句的执行并无区别, 在本质上看,其实函数中的php语句与函数外的php语句并无不同。函数体本身最大的区别,在于其执行环境的不同。 这个“执行环境”最重要的特征就是变量的作用域。大家都知道,函数内定义的变量在函数体外是无法直接使用的,反之也是一样。那么,在函数执行的时候, 进入函数前的环境信息是必须要保存的。在函数执行完毕后,这些环境信息也会被还原,使整个程序继续的执行下去。
内部函数的执行与用户函数不同。用户函数是php语句一条条“翻译”成op_line组成的一个op_array,而内部函数则是用C来实现的,因为执行环境也是C环境, 所以可以直接调用。如下面的例子:
<?php $foo = 'test'; print_r($foo); ?>
生成的opcodes中,内部函数和用户函数的处理都是由DO_FCALL来进行的。而在其具体实现的zend_do_fcall_common_helper_SPEC()中, 则对是否为内部函数进行了判断,如果是内部函数,则使用一个比较长的调用
((zend_internal_function *) EX(function_state).function)->handler(opline->extended_value, EX_T(opline->result.u.var).var.ptr, EX(function_state).function->common .return_reference?&EX_T(opline->result.u.var).var.ptr:NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
上面这种方式的内部函数是在zend_execute_internal函数没有定义的情况下。而在而在Zend/zend.c文件的zend_startup函数中,
zend_execute_internal = NULL;
此函数确实被赋值为NULL。于是我们在if (!zend_execute_internal)判断时会成立,所以我们是执行那段很长的调用。 那么,这段很长的调用到底是什么呢?以我们常用的 count函数为例。在<<第一节 函数的内部结构>>中, 我们知道内部函数所在的结构体中 有一个handler指针指向此函数需要调用的内部定义的C函数。 这些内部函数在模块初始化时就以扩展的函数的形式加载到EG(function_table)。其调用顺序:
php_module_startup --> php_register_extensions --> zend_register_internal_module
--> zend_register_module_ex --> zend_register_functions
zend_register_functions(NULL, module->functions, NULL, module->type TSRMLS_CC)
在standard扩展中。module的定义为:
zend_module_entry basic_functions_module = { STANDARD_MODULE_HEADER_EX, NULL, standard_deps, "standard", /* extension name */ basic_functions, /* function list */ ... //省略}
从上面的代码可以看出,module->functions是指向basic_functions。在basic_functions.c文件中查找basic_functions的定义。
Atas ialah kandungan terperinci php自定义函数调用和执行过程详解. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas





PHP 8.4 membawa beberapa ciri baharu, peningkatan keselamatan dan peningkatan prestasi dengan jumlah penamatan dan penyingkiran ciri yang sihat. Panduan ini menerangkan cara memasang PHP 8.4 atau naik taraf kepada PHP 8.4 pada Ubuntu, Debian, atau terbitan mereka

Jika anda seorang pembangun PHP yang berpengalaman, anda mungkin merasakan bahawa anda telah berada di sana dan telah melakukannya. Anda telah membangunkan sejumlah besar aplikasi, menyahpenyahpepijat berjuta-juta baris kod dan mengubah suai sekumpulan skrip untuk mencapai op

Kod Visual Studio, juga dikenali sebagai Kod VS, ialah editor kod sumber percuma — atau persekitaran pembangunan bersepadu (IDE) — tersedia untuk semua sistem pengendalian utama. Dengan koleksi sambungan yang besar untuk banyak bahasa pengaturcaraan, Kod VS boleh menjadi c

JWT adalah standard terbuka berdasarkan JSON, yang digunakan untuk menghantar maklumat secara selamat antara pihak, terutamanya untuk pengesahan identiti dan pertukaran maklumat. 1. JWT terdiri daripada tiga bahagian: header, muatan dan tandatangan. 2. Prinsip kerja JWT termasuk tiga langkah: menjana JWT, mengesahkan JWT dan muatan parsing. 3. Apabila menggunakan JWT untuk pengesahan di PHP, JWT boleh dijana dan disahkan, dan peranan pengguna dan maklumat kebenaran boleh dimasukkan dalam penggunaan lanjutan. 4. Kesilapan umum termasuk kegagalan pengesahan tandatangan, tamat tempoh, dan muatan besar. Kemahiran penyahpepijatan termasuk menggunakan alat debugging dan pembalakan. 5. Pengoptimuman prestasi dan amalan terbaik termasuk menggunakan algoritma tandatangan yang sesuai, menetapkan tempoh kesahihan dengan munasabah,

Tutorial ini menunjukkan cara memproses dokumen XML dengan cekap menggunakan PHP. XML (bahasa markup extensible) adalah bahasa markup berasaskan teks yang serba boleh yang direka untuk pembacaan manusia dan parsing mesin. Ia biasanya digunakan untuk penyimpanan data

Rentetan adalah urutan aksara, termasuk huruf, nombor, dan simbol. Tutorial ini akan mempelajari cara mengira bilangan vokal dalam rentetan yang diberikan dalam PHP menggunakan kaedah yang berbeza. Vokal dalam bahasa Inggeris adalah a, e, i, o, u, dan mereka boleh menjadi huruf besar atau huruf kecil. Apa itu vokal? Vokal adalah watak abjad yang mewakili sebutan tertentu. Terdapat lima vokal dalam bahasa Inggeris, termasuk huruf besar dan huruf kecil: a, e, i, o, u Contoh 1 Input: String = "TutorialSpoint" Output: 6 menjelaskan Vokal dalam rentetan "TutorialSpoint" adalah u, o, i, a, o, i. Terdapat 6 yuan sebanyak 6

Mengikat statik (statik: :) Melaksanakan pengikatan statik lewat (LSB) dalam PHP, yang membolehkan kelas panggilan dirujuk dalam konteks statik dan bukannya menentukan kelas. 1) Proses parsing dilakukan pada masa runtime, 2) Cari kelas panggilan dalam hubungan warisan, 3) ia boleh membawa overhead prestasi.

Apakah kaedah sihir PHP? Kaedah sihir PHP termasuk: 1. \ _ \ _ Membina, digunakan untuk memulakan objek; 2. \ _ \ _ Destruct, digunakan untuk membersihkan sumber; 3. \ _ \ _ Call, mengendalikan panggilan kaedah yang tidak wujud; 4. \ _ \ _ Mendapatkan, melaksanakan akses atribut dinamik; 5. \ _ \ _ Set, melaksanakan tetapan atribut dinamik. Kaedah ini secara automatik dipanggil dalam situasi tertentu, meningkatkan fleksibiliti dan kecekapan kod.
