估计是和if
之类同级别的某种语法吧,而不是函数。在语法分析里会有单独的分支。
感觉早期编程语言容易出现特殊语法。比如:
Mid(Str, 2, 3) = "替换" ' 将 Str 第 2 ~ 4 个字符替换为“替换”
Name "C:\旧路径\旧文件.txt" As "C:\新文件.txt" ' 移动文件
Open "C:\文件.bin" For Binary Access Read Lock Read As #1 ' 二进制模式独占打开文件
Print Spc(3); "hello"; Tab(15); ; ; ; "world" ' 空 3 格,输出 hello,再定位至 15 列,输出 world
PSet (15, 20), &HFF ' 在 x = 15, y = 20 处画个红色的点
Line (15, 20)-(30, 45), vbBlue ' 画条蓝色的线
Line (15, 20)-Step(10, 10), vbGreen, B ' 在 x = 15, y = 20 处,画个绿色的,10 x 10 的框框
Line (15, 20)-Step(10, 10), vbGreen, BF ' 在 x = 15, y = 20 处,画个绿色的,10 x 10 的实心框框
SELECT CAST(... AS ...),
DATE_ADD(..., INTERVAL ... DAY),
EXTRACT(DAY_MINUTE FROM ...),
FROM JSON_TABLE(
...,
"$[*]"
COLUMNS(
rowid FOR ORDINALITY,
a VARCHAR(10) PATH "$.a" DEFAULT '123' ON EMPTY DEFAULT '456' ON ERROR,
b JSON PATH "$.b" DEFAULT '{"key": 789}' ON EMPTY,
c INT EXISTS PATH "$.c"
)
) AS tt;
让echo
具有返回值从而可以用于a || b
表达式并不难(print
就可以),但是会影响性能。所以PHP选择保持echo
无返回值(于是不能用于求值表达式,比如a || b
、a && b
),并且添加了单独的print
语言结构用于这类场景。
print
语言结构之所以“总是返回1
”,就是因为它的应用场景要求它必须有一个返回值,而且最好是真值。
如果print
返回0
,以下代码不能按预期运行:
do() && print('ok') || print('fail');
<?php
mt_srand(strtotime('2022-08-11 20:00:00'));
for ($uid = 1; $uid <= 10000000; ++$uid)
for ($i = mt_rand(15, 25); $i > 0; --$i)
...
echo $uid . ',' . mt_rand(0, 255) . "\n";
$ time php main.php > /dev/null
real 8m41.194s
user 2m50.391s
sys 5m50.391s
printf($uid . ',' . mt_rand(0, 255) . "\n");
$ time php main.php > /dev/null
real 9m39.083s
user 3m15.938s
sys 6m23.078s
PHP
版本$ php --version
PHP 8.1.5 (cli) (built: May 16 2022 17:15:25) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.5, Copyright (c) Zend Technologies
with Zend OPcache v8.1.5, Copyright (c), by Zend Technologies
with Xdebug v3.1.2, Copyright (c) 2002-2021, by Derick Rethans
@老虎会游泳,上面有点乱,重新写成个shell
,减少数据量来测试:
echo
和有格式化参数的printf
几乎一样快printf
直接输出稍慢一点点儿 (扫描参数字符串导致的慢?)echo
非常慢,4倍耗时左右<echo $uid . ',' . mt_rand(0, 255) . "\n">
2000232 18919812
real 0m5.687s
user 0m1.984s
sys 0m9.078s
<echo $uid , ',' , mt_rand(0, 255) , "\n">
2000232 18919812
real 0m22.305s
user 0m8.547s
sys 0m35.875s
<printf($uid . ',' . mt_rand(0, 255) . "\n")>
2000232 18919812
real 0m5.817s
user 0m2.484s
sys 0m8.563s
<printf("%d,%d\n", $uid, mt_rand(0, 255))>
2000232 18919812
real 0m5.694s
user 0m2.172s
sys 0m9.000s
bash
源码while read -r code; do
echo $'\n'"<$code>"
time php <<-EOF | wc -lc
<?php
mt_srand(strtotime('2022-08-11 20:00:00'));
for (\$uid = 1; \$uid <= 100000; ++\$uid)
for (\$i = mt_rand(15, 25); \$i > 0; --\$i)
$code;
EOF
done <<-'EOF'
echo $uid . ',' . mt_rand(0, 255) . "\n"
echo $uid , ',' , mt_rand(0, 255) , "\n"
printf($uid . ',' . mt_rand(0, 255) . "\n")
printf("%d,%d\n", $uid, mt_rand(0, 255))
EOF
echo是一个没有返回值的语言结构,就算加括号也不能改变这一点。
因为没有返回值,所以无法用于
a || b
表达式。这和函数不同,函数总是有返回值,函数不加return
的情况下只是返回null
,不像echo
完全没有返回值。因为完全没有返回值,所以任何尝试捕获其返回值的表达式都会语法错误。要让
a || echo 'xxx'
成立,echo 'xxx'
必须有返回值,因为该表达式的本义是求a
和echo 'xxx'
的逻辑或值,而||
的右侧不可求值,所以语法错误。想要用于
a || b
表达式,可以改用print
(有返回值的语言结构)或printf
(普通函数)。https://php.net/echo
https://php.net/print
https://php.net/printf
从上面可以看出,PHP中的
a || b
表达式并不是if (!a) b
的良好替代品,因为这么用完全依赖语句的“副作用”,是当a
为假时,需要对b
求值,所以才执行了b
的代码。而如果b
不可求值,代码就会语法错误。