溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

echo在php中什么意思

發(fā)布時(shí)間:2021-06-02 09:35:53 來(lái)源:億速云 閱讀:324 作者:栢白 欄目:編程語(yǔ)言

這篇文章主要介紹了echo在php中什么意思,具有一定借鑒價(jià)值,需要的朋友可以參考下。下面就和我一起來(lái)看看吧。

1、概述

echo 作為PHP中的語(yǔ)言結(jié)構(gòu), 經(jīng)常會(huì)被使用, 因此了解他的實(shí)現(xiàn)還是有必要的.

版本源碼地址
PHP-7.2.8https://github.com/php/php-src/tree/PHP-7.2.8/

2、官方文檔(php.net)

2.1 輸出一個(gè)或多個(gè)字符串

void echo ( string $arg1 [, string $... ] )
  • 文檔地址:http://php.net/manual/zh/function.echo.php

2.2 說(shuō)明

echo 不是一個(gè)函數(shù),是一個(gè)PHP的語(yǔ)言結(jié)構(gòu),因此不一定要使用小括號(hào)來(lái)指明參數(shù),單引號(hào)、雙引號(hào)都行.echo 不表現(xiàn)得像一個(gè)函數(shù),所以不能總是使用一個(gè)函數(shù)的上下文。echo 輸出多個(gè)字符串的時(shí)候, 不能使用小括號(hào)。echo 在php.ini中啟用 short_open_tag 時(shí),有一個(gè)快捷用法(view層)<?= 'Hello World'; ?>echoprint 最主要的不同之處是, echo 接受參數(shù)列表,并且沒(méi)有返回值。

2.3 注釋

Note: 因?yàn)槭且粋€(gè)語(yǔ)言構(gòu)造器而不是一個(gè)函數(shù),不能被 可變函數(shù) 調(diào)用。

<?php

/**
 * Tip
 * 相對(duì) echo 中拼接字符串而言,傳遞多個(gè)參數(shù)比較好,考慮到了 PHP 中連接運(yùn)算符(“.”)的優(yōu)先級(jí)。 傳入多個(gè)參數(shù),不需要圓括號(hào)保證優(yōu)先級(jí):
 */
echo "Sum: ", 1 + 2;
echo "Hello ", isset($name) ? $name : "John Doe", "!";

/** Tip
 * 如果是拼接的,相對(duì)于加號(hào)和三目元算符,連接運(yùn)算符(“.”)具有更高優(yōu)先級(jí)。為了正確性,必須使用圓括號(hào):
 */
echo 'Sum: ' . (1 + 2);
echo 'Hello ' . (isset($name) ? $name : 'John Doe') . '!';

3、應(yīng)用

3.1 輸出基本數(shù)據(jù)類型

echo 123, 'abc', [12, 34];  // 123abcArray

echo "Sum: ", 1 + 2; // Sum: 3
echo 'Sum: ' . (1 + 2); // Sum: 3

echo "Hello ", isset($name) ? $name : "John Doe", "!"; // Hello John Doe!
echo 'Hello ' . (isset($name) ? $name : 'John Doe') . '!'; // Hello John Doe!

3.2 輸出對(duì)象類型

<?php 
class Customer {
    public function say() {
        return 'Hello World';
    }
}

echo (new Customer());

Catchable fatal error: Object of class Customer could not be converted to string in /usercode/file.php on line 8

輸出對(duì)象時(shí)匯報(bào)以上錯(cuò)誤, 所以如果需要輸出對(duì)象, 一定要在其內(nèi)部實(shí)現(xiàn) __toString()。

<?php 
class Customer {
    public function say() {
        return 'Hello World';
    }
    
    /**
     * __toString() 方法用于一個(gè)類被當(dāng)成字符串時(shí)應(yīng)怎樣回應(yīng)。例如 echo $obj; 應(yīng)該顯示些什么。此方法必須返回一個(gè)字符串,否則將發(fā)出一條 E_RECOVERABLE_ERROR 級(jí)別的致命錯(cuò)誤。
     */
    public function __toString(){
        return $this->say();
    }
}

echo (new Customer()); // Hello World

3.3 輸出資源類型

echo tmpfile(); // Resource id #1

4、源碼

4.1 源碼概述

php 是一門腳本語(yǔ)言, 所以所有的符號(hào)都會(huì)先經(jīng)過(guò)詞法解析和語(yǔ)法解析階段, 這兩個(gè)階段由lex & yacc 完成。

在計(jì)算機(jī)科學(xué)里面,lex是一個(gè)產(chǎn)生詞法分析器的程序。 Lex常常與yacc 語(yǔ)法分析器產(chǎn)生程序一起使用。Lex是許多UNIX系統(tǒng)的標(biāo)準(zhǔn)詞法分析器產(chǎn)生程序,而且這個(gè)工具所作的行為被詳列為POSIX標(biāo)準(zhǔn)的一部分。 Lex讀進(jìn)一個(gè)代表詞法分析器規(guī)則的輸入字符串流,然后輸出以C語(yǔ)言實(shí)做的詞法分析器源代碼。 --維基百科

對(duì)應(yīng)的文件在 Zend/zend_language_parser.yZend/zend_language_scanner.l。

4.2 字符轉(zhuǎn)標(biāo)記(Zend/zend_language_scanner.l)

<ST_IN_SCRIPTING>"echo" {
	RETURN_TOKEN(T_ECHO);
}

ZEND引擎在讀取一個(gè)PHP文件之后會(huì)先進(jìn)行詞法分析,就是用lex掃描,把對(duì)應(yīng)的PHP字符轉(zhuǎn)換成相應(yīng)的標(biāo)記(也叫token),比如 echo $a; 在碰到這句首先會(huì)匹配到echo,符合上面的規(guī)則,然后就返回一個(gè) T_ECHO 標(biāo)記,這個(gè)在后面的語(yǔ)法分析會(huì)用上,也就是在 zend_language_parser.y 文件中

4.3 語(yǔ)法分析(Zend/zend_language_parser.y)

# %token Token就是一個(gè)個(gè)的“詞塊”
%token T_ECHO       "echo (T_ECHO)"

# statement T_ECHO echo_expr_list
statement:
		'{' inner_statement_list '}' { ? = $2; }
	|	if_stmt { ? = $1; }
	|	alt_if_stmt { ? = $1; }
	|	T_WHILE '(' expr ')' while_statement
			{ ? = zend_ast_create(ZEND_AST_WHILE, $3, $5); }
	|	T_DO statement T_WHILE '(' expr ')' ';'
			{ ? = zend_ast_create(ZEND_AST_DO_WHILE, $2, $5); }
	|	T_FOR '(' for_exprs ';' for_exprs ';' for_exprs ')' for_statement
			{ ? = zend_ast_create(ZEND_AST_FOR, $3, $5, $7, $9); }
	|	T_SWITCH '(' expr ')' switch_case_list
			{ ? = zend_ast_create(ZEND_AST_SWITCH, $3, $5); }
	|	T_BREAK optional_expr ';'		{ ? = zend_ast_create(ZEND_AST_BREAK, $2); }
	|	T_CONTINUE optional_expr ';'	{ ? = zend_ast_create(ZEND_AST_CONTINUE, $2); }
	|	T_RETURN optional_expr ';'		{ ? = zend_ast_create(ZEND_AST_RETURN, $2); }
	|	T_GLOBAL global_var_list ';'	{ ? = $2; }
	|	T_STATIC static_var_list ';'	{ ? = $2; }
	|	T_ECHO echo_expr_list ';'		{ ? = $2; }
	|	T_INLINE_HTML { ? = zend_ast_create(ZEND_AST_ECHO, $1); }
	|	expr ';' { ? = $1; }
	|	T_UNSET '(' unset_variables ')' ';' { ? = $3; }
	|	T_FOREACH '(' expr T_AS foreach_variable ')' foreach_statement
			{ ? = zend_ast_create(ZEND_AST_FOREACH, $3, $5, NULL, $7); }
	|	T_FOREACH '(' expr T_AS foreach_variable T_DOUBLE_ARROW foreach_variable ')'
		foreach_statement
			{ ? = zend_ast_create(ZEND_AST_FOREACH, $3, $7, $5, $9); }
	|	T_DECLARE '(' const_list ')'
			{ zend_handle_encoding_declaration($3); }
		declare_statement
			{ ? = zend_ast_create(ZEND_AST_DECLARE, $3, $6); }
	|	';'	/* empty statement */ { ? = NULL; }
	|	T_TRY '{' inner_statement_list '}' catch_list finally_statement
			{ ? = zend_ast_create(ZEND_AST_TRY, $3, $5, $6); }
	|	T_THROW expr ';' { ? = zend_ast_create(ZEND_AST_THROW, $2); }
	|	T_GOTO T_STRING ';' { ? = zend_ast_create(ZEND_AST_GOTO, $2); }
	|	T_STRING ':' { ? = zend_ast_create(ZEND_AST_LABEL, $1); }
;

statement 看到了 T_ECHO, 后面跟著 echo_expr_list,再搜這個(gè)字符串,找到如下代碼:

# echo_expr_list
echo_expr_list:
    echo_expr_list ',' echo_expr { ? = zend_ast_list_add($1, $3); }
  | echo_expr { ? = zend_ast_create_list(1, ZEND_AST_STMT_LIST, $1); }
;

echo_expr:
  expr { ? = zend_ast_create(ZEND_AST_ECHO, $1); }
;

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

詞法分析后得到單獨(dú)存在的詞塊不能表達(dá)完整的語(yǔ)義,還需要借助規(guī)則進(jìn)行組織串聯(lián)。語(yǔ)法分析器就是這個(gè)組織者。它會(huì)檢查語(yǔ)法、匹配Token,對(duì)Token進(jìn)行關(guān)聯(lián)。PHP7中,組織串聯(lián)的產(chǎn)物就是抽象語(yǔ)法樹(shù)(Abstract Syntax Tree,AST), 詳情請(qǐng)查看相關(guān)源碼: 抽象語(yǔ)法樹(shù)(Abstract Syntax Tree,AST)

這么看比較難理解,接下來(lái)我們從一個(gè)簡(jiǎn)單的例子看下最終生成的語(yǔ)法樹(shù)。

$a = 123;
$b = "hi~";

echo $a,$b;

具體解析過(guò)程這里不再解釋,有興趣的可以翻下zend_language_parse.y中,這個(gè)過(guò)程不太容易理解,需要多領(lǐng)悟幾遍,最后生成的ast如下圖:

echo在php中什么意思

4.4 模塊初始化(main/main.c)

通過(guò) write_function 綁定PHP輸出函 數(shù)php_output_wrapperzend_utility_functions結(jié)構(gòu)體, 此結(jié)構(gòu)體會(huì)在xx被使用

# php_module_startup

zend_utility_functions zuf;

// ...

gc_globals_ctor();

zuf.error_function = php_error_cb;
zuf.printf_function = php_printf;
zuf.write_function = php_output_wrapper;
zuf.fopen_function = php_fopen_wrapper_for_zend;
zuf.message_handler = php_message_handler_for_zend;
zuf.get_configuration_directive = php_get_configuration_directive_for_zend;
zuf.ticks_function = php_run_ticks;
zuf.on_timeout = php_on_timeout;
zuf.stream_open_function = php_stream_open_for_zend;
zuf.printf_to_smart_string_function = php_printf_to_smart_string;
zuf.printf_to_smart_str_function = php_printf_to_smart_str;
zuf.getenv_function = sapi_getenv;
zuf.resolve_path_function = php_resolve_path_for_zend;
zend_startup(&zuf, NULL);

zuf 是一個(gè) zend_utility_functions 結(jié)構(gòu)體,這樣就把php_output_wrapper函數(shù)傳給了zuf.write_function,后面還有好幾層包裝,最后的實(shí)現(xiàn)也是在main/main.c文件里面實(shí)現(xiàn)的,是下面這個(gè)函數(shù):

/* {{{ php_output_wrapper
 */
static size_t php_output_wrapper(const char *str, size_t str_length)
{
	return php_output_write(str, str_length);
}

php_out_wrapper 中調(diào)用的 php_output_writemain/output.c 中實(shí)現(xiàn), 實(shí)現(xiàn)代碼如下:

/* {{{ int php_output_write(const char *str, size_t len)
 * Buffered write 
 * #define PHP_OUTPUT_ACTIVATED        0x100000 
 * 當(dāng)flags=PHP_OUTPUT_ACTIVATED,會(huì)調(diào)用sapi_module.ub_write輸出, 每個(gè)SAPI都有自已的實(shí)現(xiàn), cli中是調(diào)用sapi_cli_single_write()
 *  php_output_write(); //輸出,有buffer, 調(diào)用php_output_op()
 *  php_output_write_unbuffered();//輸出,沒(méi)有buffer,調(diào)用PHP_OUTPUT_ACTIVATED,會(huì)調(diào)用sapi_module.ub_write
 *  php_output_set_status(); //用于SAPI設(shè)置output.flags
 *  php_output_get_status(); //獲取output.flags的值
 */
PHPAPI size_t php_output_write(const char *str, size_t len)
{
	if (OG(flags) & PHP_OUTPUT_ACTIVATED) {
		php_output_op(PHP_OUTPUT_HANDLER_WRITE, str, len);
		return len;
	}
	if (OG(flags) & PHP_OUTPUT_DISABLED) {
		return 0;
	}
	return php_output_direct(str, len);
}
/* }}} */

4.5 輸出的終點(diǎn)(main/output.c fwrite函數(shù))

不調(diào)用sapi_module的輸出

static size_t (*php_output_direct)(const char *str, size_t str_len) = php_output_stderr;

static size_t php_output_stderr(const char *str, size_t str_len)
{
	fwrite(str, 1, str_len, stderr);
/* See http://support.microsoft.com/kb/190351 */
#ifdef PHP_WIN32
	fflush(stderr);
#endif
	return str_len;
}

調(diào)用sapi_module的輸出

sapi_module.ub_write(context.out.data, context.out.used);

if (OG(flags) & PHP_OUTPUT_IMPLICITFLUSH) {
	sapi_flush();
}

php_output_op 詳細(xì)實(shí)現(xiàn)如下:

/* {{{ static void php_output_op(int op, const char *str, size_t len)
 * Output op dispatcher, passes input and output handlers output through the output handler stack until it gets written to the SAPI 
 */
static inline void php_output_op(int op, const char *str, size_t len)
{
	php_output_context context;
	php_output_handler **active;
	int obh_cnt;

	if (php_output_lock_error(op)) {
		return;
	}

	php_output_context_init(&context, op);

	/*
	* broken up for better performance:
	*  - apply op to the one active handler; note that OG(active) might be popped off the stack on a flush
	*  - or apply op to the handler stack
	*/
	if (OG(active) && (obh_cnt = zend_stack_count(&OG(handlers)))) {
		context.in.data = (char *) str;
		context.in.used = len;

		if (obh_cnt > 1) {
			zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_op, &context);
		} else if ((active = zend_stack_top(&OG(handlers))) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) {
			php_output_handler_op(*active, &context);
		} else {
			php_output_context_pass(&context);
		}
	} else {
		context.out.data = (char *) str;
		context.out.used = len;
	}

	if (context.out.data && context.out.used) {
		php_output_header();

		if (!(OG(flags) & PHP_OUTPUT_DISABLED)) {
#if PHP_OUTPUT_DEBUG
			fprintf(stderr, "::: sapi_write('%s', %zu)\n", context.out.data, context.out.used);
#endif
			sapi_module.ub_write(context.out.data, context.out.used);

			if (OG(flags) & PHP_OUTPUT_IMPLICITFLUSH) {
				sapi_flush();
			}

			OG(flags) |= PHP_OUTPUT_SENT;
		}
	}
	php_output_context_dtor(&context);
}

以上了解了PHP輸出函數(shù)的實(shí)現(xiàn), 接下來(lái)了解echo實(shí)現(xiàn).

4.6 輸出動(dòng)作的ZEND引擎實(shí)現(xiàn)(Zend/zend_vm_def.h)

ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMPVAR|CV, ANY)
{
	USE_OPLINE
	zend_free_op free_op1;
	zval *z;

	SAVE_OPLINE();
	z = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);

	if (Z_TYPE_P(z) == IS_STRING) {
		zend_string *str = Z_STR_P(z);

		if (ZSTR_LEN(str) != 0) {
			zend_write(ZSTR_VAL(str), ZSTR_LEN(str));
		}
	} else {
		zend_string *str = _zval_get_string_func(z);

		if (ZSTR_LEN(str) != 0) {
			zend_write(ZSTR_VAL(str), ZSTR_LEN(str));
		} else if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(z) == IS_UNDEF)) {
			GET_OP1_UNDEF_CV(z, BP_VAR_R);
		}
		zend_string_release(str);
	}

	FREE_OP1();
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

可以看到在 zend vm 中通過(guò)調(diào)用zend_write來(lái)實(shí)現(xiàn)輸出,接下來(lái)看下zend_write的實(shí)現(xiàn)。

4.7 zend_write實(shí)現(xiàn)(Zend/zend.c)

# Zend/zend.h
typedef int (*zend_write_func_t)(const char *str, size_t str_length);

# Zend/zend.c
ZEND_API zend_write_func_t zend_write;

# 如下圖所示, zend_write的初始化是在zend_startup()函數(shù)里面,這是zend引擎啟動(dòng)的時(shí)候需要做的一些初始化工作,有下面一句:

zend_write = (zend_write_func_t) utility_functions->write_function; // php_output_wrapper

zend_utility_functions *utility_functionsmain/main.c php_module_startup()zuf中被定義:

zuf.write_function = php_output_wrapper;

echo在php中什么意思

5、php(echo)加速

5.1 PHP echo 真的慢么?

echo在php中什么意思

echo 輸出大字符串(500K)的時(shí)候,執(zhí)行時(shí)間會(huì)明顯變長(zhǎng),所以會(huì)被認(rèn)為PHP的echo性能很差, 實(shí)際上這并不是語(yǔ)言(PHP)問(wèn)題, 而是一個(gè)IO問(wèn)題(IO的速度限制了輸出的速度)。

但是在某些時(shí)候echo執(zhí)行時(shí)間過(guò)長(zhǎng), 會(huì)影響其他的服務(wù), 進(jìn)而影響整個(gè)系統(tǒng)。

那么使用 apache 時(shí)如何優(yōu)化使的 echo 變快, 讓PHP的請(qǐng)求處理過(guò)程盡快結(jié)束?

5.2 還是可以優(yōu)化的: 打開(kāi)輸出緩存

echo慢是在等待“寫數(shù)據(jù)”成功返回, 所以可打開(kāi)輸出緩存:

# 編輯php.ini
output_buffering = 4096 //bytes

# 調(diào)用ob_start()
ob_start();
echo $hugeString;
ob_end_flush();

ob_start() 會(huì)開(kāi)辟一塊4096大小的buffer,所以如果 $hugeString 大于 4096,將不會(huì)起到加速作用。

echo 會(huì)立即執(zhí)行成功返回, 因?yàn)閿?shù)據(jù)暫時(shí)寫到了我們的輸出緩存中,如果buffer足夠大,那么內(nèi)容會(huì)等到腳本的最后,才一次性的發(fā)送給客戶端(嚴(yán)格的說(shuō)是發(fā)給webserver)。

6、輸出時(shí)的類型轉(zhuǎn)換

6.1 輸出時(shí)的類型轉(zhuǎn)換規(guī)則

inputoutputdesccode
BooleanString1 或 0echo true; // 1
IntegerInteger不轉(zhuǎn)換echo 123; // 123
FloatFloat不轉(zhuǎn)換, 注意精度問(wèn)題echo 123.234; // 123.234
StringString不轉(zhuǎn)換echo 'abcd'; // abcd
ArrayArray-echo [12, 34]; // Array
ObjectCatchable fatal errorObject of class stdClass could not be converted to string in file.php on line *echo json_decode(json_encode(['a' => 'b']));
ResourceResource id #1-echo tmpfile(); // Resource id #1
NULLstring轉(zhuǎn)為空字符串echo null; // 空字符串

6.2 輸出時(shí)的類型轉(zhuǎn)換源碼(Zend/zend_operators.h & Zend/zend_operators.c)

# Zend/zend_operators.h
ZEND_API zend_string* ZEND_FASTCALL _zval_get_string_func(zval *op);

# Zend/zend_operators.c
ZEND_API zend_string* ZEND_FASTCALL _zval_get_string_func(zval *op) /* {{{ */
{
try_again:
	switch (Z_TYPE_P(op)) {
		case IS_UNDEF:
		case IS_NULL:
		case IS_FALSE:
			return ZSTR_EMPTY_ALLOC();
		case IS_TRUE:
			if (CG(one_char_string)['1']) {
				return CG(one_char_string)['1'];
			} else {
				return zend_string_init("1", 1, 0);
			}
		case IS_RESOURCE: {
			char buf[sizeof("Resource id #") + MAX_LENGTH_OF_LONG];
			int len;

			len = snprintf(buf, sizeof(buf), "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
			return zend_string_init(buf, len, 0);
		}
		case IS_LONG: {
			return zend_long_to_str(Z_LVAL_P(op));
		}
		case IS_DOUBLE: {
			return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op));
		}
		case IS_ARRAY:
			zend_error(E_NOTICE, "Array to string conversion");
			return zend_string_init("Array", sizeof("Array")-1, 0);
		case IS_OBJECT: {
			zval tmp;
			if (Z_OBJ_HT_P(op)->cast_object) {
				if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) {
					return Z_STR(tmp);
				}
			} else if (Z_OBJ_HT_P(op)->get) {
				zval *z = Z_OBJ_HT_P(op)->get(op, &tmp);
				if (Z_TYPE_P(z) != IS_OBJECT) {
					zend_string *str = zval_get_string(z);
					zval_ptr_dtor(z);
					return str;
				}
				zval_ptr_dtor(z);
			}
			zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
			return ZSTR_EMPTY_ALLOC();
		}
		case IS_REFERENCE:
			op = Z_REFVAL_P(op);
			goto try_again;
		case IS_STRING:
			return zend_string_copy(Z_STR_P(op));
		EMPTY_SWITCH_DEFAULT_CASE()
	}
	return NULL;
}
/* }}} */

7、Zend/zend_compile.c對(duì)echo的解析

7.1 源碼地址

  • PHP源碼地址 zend_compile.h

  • PHP源碼地址 zend_compile.c

7.2 zend_compile_expr 實(shí)現(xiàn)

# Zend/zend_compile.h
void zend_compile_expr(znode *node, zend_ast *ast);

# Zend/zend_compile.c
void zend_compile_expr(znode *result, zend_ast *ast) /* {{{ */
{
	/* CG(zend_lineno) = ast->lineno; */
	CG(zend_lineno) = zend_ast_get_lineno(ast);

	switch (ast->kind) {
		case ZEND_AST_ZVAL:
			ZVAL_COPY(&result->u.constant, zend_ast_get_zval(ast));
			result->op_type = IS_CONST;
			return;
		case ZEND_AST_ZNODE:
			*result = *zend_ast_get_znode(ast);
			return;
		case ZEND_AST_VAR:
		case ZEND_AST_DIM:
		case ZEND_AST_PROP:
		case ZEND_AST_STATIC_PROP:
		case ZEND_AST_CALL:
		case ZEND_AST_METHOD_CALL:
		case ZEND_AST_STATIC_CALL:
			zend_compile_var(result, ast, BP_VAR_R);
			return;
		case ZEND_AST_ASSIGN:
			zend_compile_assign(result, ast);
			return;
		case ZEND_AST_ASSIGN_REF:
			zend_compile_assign_ref(result, ast);
			return;
		case ZEND_AST_NEW:
			zend_compile_new(result, ast);
			return;
		case ZEND_AST_CLONE:
			zend_compile_clone(result, ast);
			return;
		case ZEND_AST_ASSIGN_OP:
			zend_compile_compound_assign(result, ast);
			return;
		case ZEND_AST_BINARY_OP:
			zend_compile_binary_op(result, ast);
			return;
		case ZEND_AST_GREATER:
		case ZEND_AST_GREATER_EQUAL:
			zend_compile_greater(result, ast);
			return;
		case ZEND_AST_UNARY_OP:
			zend_compile_unary_op(result, ast);
			return;
		case ZEND_AST_UNARY_PLUS:
		case ZEND_AST_UNARY_MINUS:
			zend_compile_unary_pm(result, ast);
			return;
		case ZEND_AST_AND:
		case ZEND_AST_OR:
			zend_compile_short_circuiting(result, ast);
			return;
		case ZEND_AST_POST_INC:
		case ZEND_AST_POST_DEC:
			zend_compile_post_incdec(result, ast);
			return;
		case ZEND_AST_PRE_INC:
		case ZEND_AST_PRE_DEC:
			zend_compile_pre_incdec(result, ast);
			return;
		case ZEND_AST_CAST:
			zend_compile_cast(result, ast);
			return;
		case ZEND_AST_CONDITIONAL:
			zend_compile_conditional(result, ast);
			return;
		case ZEND_AST_COALESCE:
			zend_compile_coalesce(result, ast);
			return;
		case ZEND_AST_PRINT:
			zend_compile_print(result, ast);
			return;
		case ZEND_AST_EXIT:
			zend_compile_exit(result, ast);
			return;
		case ZEND_AST_YIELD:
			zend_compile_yield(result, ast);
			return;
		case ZEND_AST_YIELD_FROM:
			zend_compile_yield_from(result, ast);
			return;
		case ZEND_AST_INSTANCEOF:
			zend_compile_instanceof(result, ast);
			return;
		case ZEND_AST_INCLUDE_OR_EVAL:
			zend_compile_include_or_eval(result, ast);
			return;
		case ZEND_AST_ISSET:
		case ZEND_AST_EMPTY:
			zend_compile_isset_or_empty(result, ast);
			return;
		case ZEND_AST_SILENCE:
			zend_compile_silence(result, ast);
			return;
		case ZEND_AST_SHELL_EXEC:
			zend_compile_shell_exec(result, ast);
			return;
		case ZEND_AST_ARRAY:
			zend_compile_array(result, ast);
			return;
		case ZEND_AST_CONST:
			zend_compile_const(result, ast);
			return;
		case ZEND_AST_CLASS_CONST:
			zend_compile_class_const(result, ast);
			return;
		case ZEND_AST_ENCAPS_LIST:
			zend_compile_encaps_list(result, ast);
			return;
		case ZEND_AST_MAGIC_CONST:
			zend_compile_magic_const(result, ast);
			return;
		case ZEND_AST_CLOSURE:
			zend_compile_func_decl(result, ast);
			return;
		default:
			ZEND_ASSERT(0 /* not supported */);
	}
}
/* }}} */

7.3 zend_compile_echo 實(shí)現(xiàn)

# Zend/zend_compile.c
void zend_compile_echo(zend_ast *ast) /* {{{ */
{
	zend_op *opline;
	zend_ast *expr_ast = ast->child[0];

	znode expr_node;
	zend_compile_expr(&expr_node, expr_ast);

	opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL);
	opline->extended_value = 0;
}

以上就是echo在php中什么意思的詳細(xì)內(nèi)容了,看完之后是否有所收獲呢?如果想了解更多相關(guān)內(nèi)容,歡迎來(lái)億速云行業(yè)資訊!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI