【相干学习保举:php编程(视频)】
PHP函数的注册以及应用
PHP扩大的次要指标是为用户注册新的PHP函数,PHP函数十分复杂,很难齐全了解它们与Zend引擎亲密相干的机制,但侥幸的是, 咱们正在本章中没有需求这些常识,由于PHP扩大机制提供了许多办法来形象如斯复杂的内容。
正在扩大中注册并应用一个新的PHP函数是一个简略的步骤. 但是,要粗浅了解全体状况,则要复杂患上多。zend_function章节的第一步 可能会有所协助.
显然,你需求把握类型, 特地是 zendValues 以及 内存治理. 当然, 理解你的钩子.
zend_function_entry 构造
没有要以及 zend_function 构造混杂,zend_function_entry
是用正在扩大中针对引擎注册函数的。看这里:
#define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value typedef struct _zend_function_entry { const char *fname; void (*handler)(INTERNAL_FUNCTION_PARAMETERS); const struct _zend_internal_arg_info *arg_info; uint32_t num_args; uint32_t flags; } zend_function_entry;
你会发现该构造其实不复杂,这就是申明以及注册新性能所需求的。让咱们一同具体引见:
函数的名字:fname
。没甚么好增补的,你晓得它的用处对吧?只要留意是 const char *
类型。这没有实用于引擎。此 fname
是一个模子,引擎将会从 外部的 zend_string 创立。
而后来看 handler
。这是指向 C 代码的函数指针,它将会是函数的主体。这里,咱们将应用宏来简化其申明(等等会看到)。进入此函数,咱们可以解析函数接纳的参数,而且天生一个前往值,就像任何 PHP 用户区的函数。留意,这个前往值作为参数通报到咱们的解决顺序。
争执。arg_info
变量是对于申明咱们的函数将接纳的 API 参数。一样,这局部可能很难深化了解,但咱们没有需求了解太深,咱们再次应用宏进行形象以及简化参数申明。你要晓得的是,正在这里你没有需求申明任何参数便可应用该函数,然而咱们激烈倡议你这么做。咱们将回到这里。参数是一组 arg_info
,因而它的巨细作为 num_args
通报。
而后是 flags
。正在这章咱们没有具体阐明它。这些是外部应用的,你可正在 zend_function 章节理解具体信息。
注册 PHP 函数
当加载扩大时,PHP 函数会被注册到 ZEND 引擎傍边。一个扩大能够正在扩大构造中申明一个函数向量。被扩大申明的函数被称为 外围
函数,与 用户
函数(正在PHP用户中被申明以及应用的函数)相同,它们正在以后的申请完结时没有会被登记:能够不断应用。
提示一下,如下是为了不便可读性对 PHP 扩大构造的简写
struct _zend_module_entry { unsigned short size; unsigned int zend_api; unsigned char zend_debug; unsigned char zts; const struct _zend_ini_entry *ini_entry; const struct _zend_module_dep *deps; const char *name; const struct _zend_function_entry *functions; /* 函数申明向量 */ int (*module_startup_func)(INIT_FUNC_ARGS); int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); /* ... */ };
您将向函数向量通报一个已申明的函数向量。让咱们一同来看一个简略的例子:
/* pib.c 头文件*/ PHP_FUNCTION(fahrenheit_to_celsius) { } static const zend_function_entry pib_functions[] = { PHP_FE(fahrenheit_to_celsius, NULL) }; zend_module_entry pib_module_entry = { STANDARD_MODULE_HEADER, "pib", pib_functions, NULL, NULL, NULL, NULL, NULL, "0.1", STANDARD_MODULE_PROPERTIES };
咱们来尝尝一个简略的函数 fahrenheit_to_celsius()
(名字通知了咱们它的作用)
经过应用 PHP_FUNCTION()
宏来界说一个函数。后者将通报它的参数并扩大成正确的构造。而后,咱们把函数符号汇总并将其增加到 pib_functions
向量中。这就是经过 zend_module_entry
符号延长的 zend_function_entry *
类型。正在此向量中,咱们经过 PHP_FE
宏增加咱们的 PHP 函数。后者需求 PHP 函数称号,和咱们通报 NULL 值时的一个参数向量。
正在 php_pib.h 头文件中,咱们应该像 C 言语同样正在这里申明咱们的函数:
/* pib.h 头文件*/ PHP_FUNCTION(fahrenheit_to_celsius);
如你所见,申明函数的确很容易。宏为咱们干完了一切难活。如下是以及上文相反的代码,然而却扩大了宏,因而你能够看下它们是若何运转的:
/* pib.c */ void zif_fahrenheit_to_celsius(zend_execute_data *execute_data, zval *return_value) { } static const zend_function_entry pib_functions[] = { { "fahrenheit_to_celsius", zif_fahrenheit_to_celsius, ((void *)0), (uint32_t) (sizeof(((void *)0))/sizeof(struct _zend_internal_arg_info)-1), 0 }, }
请留意 PHP_FUNCTION()
是若何以 zif_
扫尾扩大为 C 符号的。‘zif’ 被增加到你的函数称号中,以避免PHP 及其模块正在编译中造成符号称号抵触。因而,咱们的 fahrenheit_to_celsius()
PHP 函数应用了 zif_fahrenheit_to_celsius()
的解决顺序。它简直以及每一个 PHP 函数同样。假如你搜寻 zif_var_dump
,就能够浏览PHP var_dump()
的源码函数等。
申明函数参数
到今朝为止,假如 「你编译」 扩大并将其加载到PHP中,你能够瞥见函数出现的反射机制:
> ~/php/bin/php -dextension=pib.so --re pib Extension [ <persistent> extension #37 pib version 0.1 ] { - Functions { Function [ <internal:pib> function fahrenheit_to_celsius ] { } }
然而它短少参数。假如咱们公布一个 fahrenheit_to_celsius($fahrenheit)
函数署名,则需求一个强迫参数。
你必需理解,函数申明以及函数外部的运转有关。这象征着即使不申明参数,咱们如今编写函数也可能会起作用。
留意
申明参数尽管没有是强迫性的,然而咱们激烈保举应用。反射 API 可经过应用参数猎取函数的信息。Zend 引擎也用到参数,尤为是当咱们谈及援用传参或许前往援用的函数时。
要申明参数,咱们必需要相熟 zend_internal_arg_info
构造:
typedef struct _zend_internal_arg_info { const char *name; const char *class_name; zend_uchar type_hint; zend_uchar pass_by_reference; zend_bool allow_null; zend_bool is_variadic; } zend_internal_arg_info;
没须要具体阐明每一个字段,然而想要了解参数却比这类独自构造复杂患上多。侥幸的是,咱们再次为你提供了一些宏来形象这艰巨的工作。
ZEND_BEGIN_ARG_INFO_EX(arginfo_fahrenheit_to_celsius, 0, 0, 1) ZEND_ARG_INFO(0, fahrenheit) ZEND_END_ARG_INFO()
下面的代码具体的阐明了若何创立参数,但当咱们扩大宏时,咱们会感应有些艰难:
static const zend_internal_arg_info arginfo_fahrenheit_to_celsius[] = { { (const char*)(zend_uintptr_t)(1), ((void *)0), 0, 0, 0, 0 }, { "fahrenheit", ((void *)0), 0, 0, 0, 0 }, };
正如咱们所见,宏创立了一个 zend_internal_arg_info
构造。假如你浏览过这种宏的 API,那末对咱们来讲所有都变患上分明了:
/* API only */ #define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) #define ZEND_ARG_INFO(pass_by_ref, name) #define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) #define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) #define ZEND_ARG_CALLABLE_INFO(pass_by_ref, name, allow_null) #define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) #define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name)
这一系列的宏能够让你解决每一个用例。
This bunch of macros allow you to deal with every use-case.
ZEND_BEGIN_ARG_INFO_EX()
容许你申明你的函数能接纳几何个须要参数。它还容许你申明一个 &return_by_ref() 函数。- 那末你每一个参数都需求
ZEND_ARG_***_INFO()
之一。应用它你能够判别参数能否为 &$passed_by_ref 和能否需求类型提醒。
留意
假如你没有晓得怎么去定名参数向量符号,则一种做法是应用 ‘arginfo_[function name]’ 模式。
以是回到咱们的 fahrenheit_to_celsius()
函数,咱们这里声明一个简略的按值前往函数(十分经典的用例),此中一个参数称为 fahrenheit
,且未经过援用通报(又一次的传统用例)。
这就创立了类型 zend_internal_arg_info[]
(一个向量, 或一个数组, 都相反) 的 arginfo_fahrenheit_to_celsius
符号,如今咱们必需要应用该符号回到函数申明中来增加给它一些参数。
PHP_FE(fahrenheit_to_celsius, arginfo_fahrenheit_to_celsius)
至此咱们实现了,如今反射能够瞥见参数了,并会奉告引擎正在援用没有婚配的状况下该怎样做。太棒了!
留意
另有其余宏。
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX()
f.e. 你能够正在 Zend/zend_api.h 的源代码中找到一切这些文件。
C 言语的 PHP 函数构造以及 API
好的。上面是一个 PHP 函数。你能够应用它,并用 PHP 言语申明它(用户区):
function fahrenheit_to_celsius($fahrenheit) { return 5/9 * ($fahrenheit - 32); }
这是一个简略的函数,以便你能够了解它。这是用 C 编程时的样子:
PHP_FUNCTION(fahrenheit_to_celsius) { /* code to go here */ }
宏开展后,将失去:
void zif_fahrenheit_to_celsius(zend_execute_data *execute_data, zval *return_value) { /* code to go here */ }
劳动一下,思考一下次要差别。
起首希奇的是,正在 C 中,该函数没有会前往任何货色。那是一个 void
申明的函数,你不成以正在这里前往任何货色。然而咱们留意到咱们接纳了一个 zval *
类型的return_value
参数,看起来很没有错。用 C 编写 PHP 函数时,你将失去一个指向 zval 的前往值 ,心愿你们能玩一玩。这有更多对于 zval 的资本.
留意
正在 C 扩大中编写 PHP 函数时,你接纳作为参数的前往值,而且你没有会从 C 函数前往任何货色。
好的,第一点诠释了。第二点你可能曾经猜到了:PHP 函数的参数正在那里?$fahreinheit
正在那里?很难诠释齐全,现实上,这很难。
然而咱们没有需求正在这里理解细节。让咱们诠释下要害的概念:
- 参数曾经经过引擎推入货仓旅馆中。它们都正在内存的某个中央挨着堆放。
- 假如你的函数被挪用,这象征着不梗阻谬误,因而你能够阅读参数货仓旅馆,并读取运转时通报的参数。不只是你申明的那些,还包罗那些正在挪用函数时通报给函数的。引擎会为你解决所有。
- 为了读取参数,你需求一个函数或许宏,而且需求晓得有几何参数曾经推入货仓旅馆中,以便晓得何时应该中止读取它们。
- 所有都依照你接纳的作为参数的
zend_execute_data *execute_data
。然而如今咱们没有具体阐明。
解析参数:zend_parse_parameters()
要读取参数,欢送应用 zend_parse_parameters()
API (称为 ‘zpp’).
留意
当正在 C 扩大中编写 PHP 函数时,多亏了
zend_parse_parameters()
函数以及它的冤家,你接纳到 PHP 函数的参数。
zend_parse_parameters()
是一个函数,它将为你到 Zend 引擎的货仓旅馆中读取参数。你要通知它要读取几何个参数,和想要它为你提供哪一种类型。该函数将依据 PHP 类型转换规定(假如需求,而且有可能的话)将参数转换为你要的类型。假如你需求一个整型,但给了一个浮点型,假如不严格的类型提醒规定被梗阻,则引擎会将浮点型转换为整型,而后给你。
让咱们来看看这个函数:
PHP_FUNCTION(fahrenheit_to_celsius) { double f; if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &f) == FAILURE) { return; } /* continue */ }
咱们心愿正在 f 变量上失去一个 double 类型。而后咱们挪用zend_parse_parameters()
。
第一个参数是运转时已给定的参数数量。ZEND_NUM_ARGS()
是一个宏,它会通知咱们,而后咱们用它去奉告 zpp() 需求读取几何个参数。
而后咱们通报一个const char *
类型的 “d” 字符串。正在这里,要求你为每个接纳的参数写一个字母,除了了一些未正在这里讲述的非凡状况。一个简略的 “d” 示意 “假如需求的话,我想要第一个接纳的参数转换为 float (double)”。
而后,正在该字符串之后通报 C 真正需求的参数,以餍足第二个参数。一个 “d” 示意 “一个 double”,而后你如今通报 double 的 地点,引擎将会填充其值。
留意
你老是将一个指针通报给要填充的数据。
你能够正在 PHP 源代码的 README.PARAMETER_PARSING_API文件中找到对于 zpp() 的字符串格局的最新协助。细心浏览,由于这是你可能搞错并造成顺序解体的一步。始终反省你的参数,始终依据你提供的格局字符串通报相反数目的参数变量,和你要求的类型相反。要符合逻辑。
一样留意一下参数解析的失常进程。zend_parse_parameters()
函数正在胜利时应前往 SUCCESS
或许正在失败时应前往FAILURE
。失败可能示意你不应用ZEND_NUM_ARGS()
值,而是手动提供一个值(坏主见)。或许正在参数解析时做错了甚么。假如是这样,那末是时分 return 了,终止以后函数(你应该从 C 函数中前往 void
,以是只需 return
)。
到今朝为止,咱们接纳了一个 double。让咱们执行数学运算并前往后果:
static double php_fahrenheit_to_celsius(double f) { return ((double)5/9) * (double)(f - 32); } PHP_FUNCTION(fahrenheit_to_celsius) { double f; if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &f) == FAILURE) { return; } RETURN_DOUBLE(php_fahrenheit_to_celsius(f)); }
如你所知的zval 的工作原理,前往值对你来讲应该很容易。你必需填写 return_value
。
一些 RETURN_***()
宏和一些RETVAL_***()
宏都是专门用来这么做的。这两个仅设置return_value
zval 的类型以及值,然而RETURN_***()
宏前面会随着一个从以后函数前往的 Creturn
。
或许,API 提供了一系列行止理息争析参数的宏。假如你对 python 款式阐明符困惑的话,那末它更具备可读性。
你需求应用如下宏来开端以及完结函数参数解析:
ZEND_PARSE_PARAMETERS_START(min_argument_count, max_argument_count) /* 需求两个参数 */ /* 这里咱们将应用参数列表 */ ZEND_PARSE_PARAMETERS_END();
可用的参数宏能够列出以下:
Z_PARAM_ARRAY() /* old "a" */ Z_PARAM_ARRAY_OR_OBJECT() /* old "A" */ Z_PARAM_BOOL() /* old "b" */ Z_PARAM_CLASS() /* old "C" */ Z_PARAM_DOUBLE() /* old "d" */ Z_PARAM_FUNC() /* old "f" */ Z_PARAM_ARRAY_HT() /* old "h" */ Z_PARAM_ARRAY_OR_OBJECT_HT() /* old "H" */ Z_PARAM_LONG() /* old "l" */ Z_PARAM_STRICT_LONG() /* old "L" */ Z_PARAM_OBJECT() /* old "o" */ Z_PARAM_OBJECT_OF_CLASS() /* old "O" */ Z_PARAM_PATH() /* old "p" */ Z_PARAM_PATH_STR() /* old "P" */ Z_PARAM_RESOURCE() /* old "r" */ Z_PARAM_STRING() /* old "s" */ Z_PARAM_STR() /* old "S" */ Z_PARAM_ZVAL() /* old "z" */ Z_PARAM_VARIADIC() /* old "+" and "*" */
为了增加一个参数作为可选参数,咱们应用如下宏:
Z_PARAM_OPTIONAL /* old "|" */
这是基于宏的参数解析款式的示例:
PHP_FUNCTION(fahrenheit_to_celsius) { double f; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_DOUBLE(f); ZEND_PARSE_PARAMETERS_END(); RETURN_DOUBLE(php_fahrenheit_to_celsius(f)); }
增加测试
假如你已浏览无关测试的章节(看应用 .phpt 文件测试),如今你应该编写一个简略的例子:
--TEST-- Test fahrenheit_to_celsius --SKIPIF-- <?php if (!extension_loaded("pib")) print "skip"; ?> --FILE-- <?php printf("%.2f", fahrenheit_to_celsius(70)); ?> --EXPECTF-- 21.11
并启动make test
玩转常量
让咱们来看一个初级的例子。咱们来增加相同的函数:celsius_to_fahrenheit($celsius)
:
ZEND_BEGIN_ARG_INFO_EX(arginfo_celsius_to_fahrenheit, 0, 0, 1) ZEND_ARG_INFO(0, celsius) ZEND_END_ARG_INFO(); static double php_celsius_to_fahrenheit(double c) { return (((double)9/5) * c) + 32 ; } PHP_FUNCTION(celsius_to_fahrenheit) { double c; if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &c) == FAILURE) { return; } RETURN_DOUBLE(php_celsius_to_fahrenheit(c)); } static const zend_function_entry pib_functions[] = { PHP_FE(fahrenheit_to_celsius, arginfo_fahrenheit_to_celsius) /* Done above */ PHP_FE(celsius_to_fahrenheit,arginfo_celsius_to_fahrenheit) /* just added */ PHP_FE_END };
如今是一个更复杂的用例,正在将它作为 C 扩大完成以前,正在 PHP 中展现它:
const TEMP_CONVERTER_TO_CELSIUS = 1; const TEMP_CONVERTER_TO_FAHREINHEIT = 2; function temperature_converter($temp, $type = TEMP_CONVERTER_TO_CELSIUS) { switch ($type) { case TEMP_CONVERTER_TO_CELSIUS: return sprintf("%.2f degrees fahrenheit gives %.2f degrees celsius", $temp, fahrenheit_to_celsius($temp)); case TEMP_CONVERTER_TO_FAHREINHEIT: return sprintf("%.2f degrees celsius gives %.2f degrees fahrenheit, $temp, celsius_to_fahrenheit($temp)); default: trigger_error("Invalid mode provided, accepted values are 1 or 2", E_USER_WARNING); break; } }
这个例子有助于咱们引见常量。
常量正在扩大中很容易治理,就像它们正在用户区同样。常量一般为耐久性的,象征着它们应该正在申请之间放弃其值没有变。假如你晓得 PHP 的生命周期,则应该猜到 MINIT()
是向引擎注册常量的正确阶段。
正在外部,这有个常量,一个zend_constant
构造:
typedef struct _zend_constant { zval value; zend_string *name; int flags; int module_number; } zend_constant;
真的是一个简略的构造(假如你深化理解常量是若何治理到引擎中,那可能会是一场恶梦)。你申明了name
,value
,一些flags
(没有是不少),而且module_number
主动设置为你的扩大编号(不必留意它)。
要注册常量,一样的,这一点都没有难,一堆宏能够帮你实现:
#define TEMP_CONVERTER_TO_FAHRENHEIT 2 #define TEMP_CONVERTER_TO_CELSIUS 1 PHP_MINIT_FUNCTION(pib) { REGISTER_LONG_CONSTANT("TEMP_CONVERTER_TO_CELSIUS", TEMP_CONVERTER_TO_CELSIUS, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("TEMP_CONVERTER_TO_FAHRENHEIT", TEMP_CONVERTER_TO_FAHRENHEIT, CONST_CS|CONST_PERSISTENT); return SUCCESS; }
留意
给出 C 宏的 PHP 常量值是一个很好的理论。事件变患上容易了,这就是咱们做的。
依据你的常量类型,你将应用 REGISTER_LONG_CONSTANT()
、 REGISTER_DOUBLE_CONSTANT()
等等。API 以及宏位于 Zend/zend_constants.h中。
flag 正在CONST_CS
(case-sensitive constant 巨细写敏感常量,咱们想要的)以及CONST_PERSISTENT
(耐久性常量,正在申请中也是咱们想要的)之间是夹杂的 OR 操作。
如今正在 C 中的temperature_converter($temp, $type = TEMP_CONVERTER_TO_CELSIUS)
函数:
ZEND_BEGIN_ARG_INFO_EX(arginfo_temperature_converter, 0, 0, 1) ZEND_ARG_INFO(0, temperature) ZEND_ARG_INFO(0, mode) ZEND_END_ARG_INFO();
咱们失去了一个必需的参数,两个中的一个。那就是咱们申明的。其默许值没有是一个参数申明能够处理的,那将正在一秒钟内实现。
而后咱们将咱们的新函数增加到函数注册向量:
static const zend_function_entry pib_functions[] = { PHP_FE(fahrenheit_to_celsius,arginfo_fahrenheit_to_celsius) /* seen above */ PHP_FE(celsius_to_fahrenheit,arginfo_celsius_to_fahrenheit) /* seen above */ PHP_FE(temperature_converter, arginfo_temperature_converter) /* our new function */ }
函数主体:
PHP_FUNCTION(temperature_converter) { double t; zend_long mode = TEMP_CONVERTER_TO_CELSIUS; zend_string *result; if (zend_parse_parameters(ZEND_NUM_ARGS(), "d|l", &t, &mode) == FAILURE) { return; } switch (mode) { case TEMP_CONVERTER_TO_CELSIUS: result = strpprintf(0, "%.2f degrees fahrenheit gives %.2f degrees celsius", t, php_fahrenheit_to_celsius(t)); RETURN_STR(result); case TEMP_CONVERTER_TO_FAHRENHEIT: result = strpprintf(0, "%.2f degrees celsius gives %.2f degrees fahrenheit", t, php_celsius_to_fahrenheit(t)); RETURN_STR(result); default: php_error(E_WARNING, "Invalid mode provided, accepted values are 1 or 2"); } }
记患上好难看 README.PARAMETER_PARSING_API。它没有是一个很难的 API,你必需相熟它。
咱们应用 “d|l” 作为 zend_parse_parameters()
的参数。一个 double、或(管道“|”)、一个 long。留意,假如正在运转时没有提供可选参数(提示一下,ZEND_NUM_ARGS()
是甚么),则 &mode
没有会被 zpp() 涉及。这就是为何咱们提供了一个TEMP_CONVERTER_TO_CELSIUS
默许值给该变量。
而后咱们应用 strpprintf()
去构建一个 zend_string,而且应用 RETURN_STR()
前往它到 return_value
zval。
留意
strpprintf()
以及它的冤家们正在打印函数章节有诠释过。
应用 Hashtable (PHP 数组)
如今让咱们来玩一下PHP 数组并设计:
function multiple_fahrenheit_to_celsius(array $temperatures) { foreach ($temperatures as $temp) { $return[] = fahreinheit_to_celsius($temp); } return $return; }
以是正在 C 言语完成的时分,咱们需求zend_parse_parameters()
并申请一个数组,遍历它,进行数学运算,并将后果作为数组增加到 return_value
:
ZEND_BEGIN_ARG_INFO_EX(arginfo_multiple_fahrenheit_to_celsius, 0, 0, 1) ZEND_ARG_ARRAY_INFO(0, temperatures, 0) ZEND_END_ARG_INFO(); static const zend_function_entry pib_functions[] = { /* ... */ PHP_FE(multiple_fahrenheit_to_celsius, arginfo_multiple_fahrenheit_to_celsius) PHP_FE_END }; PHP_FUNCTION(multiple_fahrenheit_to_celsius) { HashTable *temperatures; zval *data; if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &temperatures) == FAILURE) { return; } if (zend_hash_num_elements(temperatures) == 0) { return; } array_init_size(return_value, zend_hash_num_elements(temperatures)); ZEND_HASH_FOREACH_VAL(temperatures, data) zval dup; ZVAL_COPY_VALUE(&dup, data); convert_to_double(&dup); add_next_index_double(return_value, php_fahrenheit_to_celsius(Z_DVAL(dup))); ZEND_HASH_FOREACH_END(); }
留意
你需求晓得 Hashtable 的工作原理,而且必读 zval 章节
正在这里,C 言语那局部将更快,由于没有需求正在 C 轮回中挪用 PHP 函数,然而一个动态(可能由编纂器内联的)函数,它的运转速率快了几个数目级,而且运转低级 CPU 指令所需的工夫也更少。这并非说这个小小的演示函数正在代码功能方面需求如斯多的存眷,只需记住为何咱们有时会应用 C 言语替代 PHP。
治理援用
如今让咱们开端玩 PHP 援用。您曾经从 zval 章节 理解到援用是正在引擎中应用的一种非凡技术。作为提示,援用(咱们指的是&$php_reference
)是调配给 zval
的,存储正在 zval
的容器中。
以是,只需记住援用是甚么和它们的设计目的,就没有难将它们解决成 PHP 函数。
假如你的函数承受一个参数作为援用,你必需正在参数署名中申明,并从你的 zend_parse_parameter()
挪用中通报一个援用。
让咱们像往常同样,起首应用 PHP 示例:因而,如今C中,起首咱们必需更改 arg_info
:
ZEND_BEGIN_ARG_INFO_EX(arginfo_fahrenheit_to_celsius, 0, 0, 1) ZEND_ARG_INFO(1, fahrenheit) ZEND_END_ARG_INFO();
" 1 ",中通报的 ZEND_ARG_INFO()
宏通知引擎必需经过援用通报参数。
而后,当咱们接纳到参数时,咱们应用 z
参数类型,以通知咱们心愿将它作为一个 zval
给出。当咱们向引擎提醒它应该向咱们通报一个援用这一现实时,咱们将取得对该 zval
的援用,也就是它的类型为is_reference
时,咱们只要要解援用它(即猎取存储到 zval
中的 zval
),并按原样修正它,由于援用的预期行为是您必需修正援用所携带的值:
PHP_FUNCTION(fahrenheit_to_celsius) { double result; zval *param; if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", ¶m) == FAILURE) { return; } ZVAL_DEREF(param); convert_to_double(param); ZVAL_DOUBLE(param, php_fahrenheit_to_celsius(Z_DVAL_P(param))); }
实现。
留意
默许
return_value
值为NULL
。假如咱们没有碰它,函数将前往PHP的NULL
。
想理解更多编程学习,敬请存眷php培训栏目!
以上就是小常识年夜学识的注册 PHP 函数的具体内容,更多请存眷资源魔其它相干文章!
标签: php开发教程 php开发资料 php开发自学 PHP函数
抱歉,评论功能暂时关闭!