作者|迪帕克·沃赫拉
译者|刘亚萌
策划|丁晓云
本文属于专题文章《PHP 8》。根据w3tech的数据,PHP仍然是Web上使用最广泛的脚本语言之一,77.3%的网站使用PHP进行服务器端编程。PHP 8带来了许多新特性和其他改进,我们将在这一系列文章中讨论。PHP 8.0增加了对几个函数和方法的支持,其中一些是对现有特性的改进,而另一些则是全新的特性。PHP 8.1中增强的可调用语法可用于通过可调用对象创建匿名函数。命名的函数参数可以和位置参数一起使用,还有一个好处,就是命名的参数没有顺序,可以通过名字来传达含义。纤程是一个可中断的功能,增加了对多任务的支持。
重新定义了私有方法上的继承
对象继承是大多数面向对象语言使用的编程范式,包括PHP。它可以重写任何扩展类的公共和受保护方法,以及类中定义的类属性和常数。在PHP中,公共方法不能通过更严格的访问来重新实现,比如将公共方法设置为私有。为了证明这一点,考虑一个扩展了类A的类B,它在类A中重新实现了一个公共方法..
& lt?phpclass A { public function sort array():string { return & # 34;A类方法& # 34;;} }类扩展了一个{ private function sort array():string { return & # 34;B类方法& # 34;;} } $ B = new B();echo $ b-& gt;sort array();运行时,该脚本将生成如下错误消息:
致命错误:B::sortArray()的访问级别必须是public(像class A一样)。公共方法不能被重新实现。相反,在类中定义的私有方法不会被继承,并且可以在扩展它的类中重新实现。例如,在下面的脚本中,类B扩展了类A,并在类A中重新实现了一个私有方法..
& lt?PHP class A { private function sort array():string { return & # 34;A类方法& # 34;;} }类扩展了一个{ private function sort array(int $ A):string { return & # 34;B类方法& # 34;;在PHP 8.0之前,对扩展类中私有方法的重新声明有两个限制:不允许改变final和static修饰符。如果私有方法被声明为final,则不允许扩展类重新声明该方法。如果私有方法被声明为静态的,它将在扩展类中保持静态。此外,如果私有方法没有静态修饰符,则扩展类不允许添加静态修饰符。在PHP 8中,这两个限制被删除了。以下脚本可以在PHP 8中正常运行。
& lt?phpclass A { private final static function sort array():string { return & # 34;A类方法& # 34;;} }类扩展了一个{ private function sort array(int $ A):string { return & # 34;B类方法& # 34;;}}PHP 8中唯一的私有方法限制是强制使用私有final构造函数。当使用静态工厂方法作为替代方法时,private final有时用于禁用构造函数。
& lt?PHP class a { private final function _ _ construct(){ } } class b扩展了一个{ private final function _ _ construct(){ } }该脚本生成以下错误消息:
致命错误:最终方法A::_ _构造()无法重写。可变参数可以替换任意数量的函数参数。在PHP 8中,单个变量参数可以替换任意数量的函数参数。考虑下面的脚本,其中类B扩展了类A,并用一个变量参数替换了函数sortArray的三个参数。
& lt?phpclass A { public function sort array(array $ arraysort,string $sortType,int $ array size){ if($ sort type = = & # 34;asc & # 34){ sort($ arrayToSort);foreach($ array sort as $ key = & gt;$ val){ echo & # 34;$ key = $ val & # 34;} } else if($ sort type = = & # 34;desc & # 34;){ rsort($ arrayToSort);foreach($ array sort as $ key = & gt;$ val){ echo & # 34;$ key = $ val & # 34;} } } }类扩展了一个{公共函数sortArray(…$ multiple){ $ arrayToSort = $ multiple[0];$ sort type = $ multiple[1];if($ sort type = = & # 34;asc & # 34){ sort($ arrayToSort);foreach($ array sort as $ key = & gt;$ val){ echo & # 34;$ key = $ val & # 34;} } else if($ sort type = = & # 34;desc & # 34;){ rsort($ arrayToSort);foreach($ array sort as $ key = & gt;$ val){ echo & # 34;$ key = $ val & # 34;}}}}可以用多个参数调用B类中的sortArray函数。
$ sortType = & # 34asc & # 34;$ arrayToSort = array(& # 34;B&第34名;, "一& # 34;, "f & # 34, "C & # 34);$ array size = 4;$ B = new B();$ b-& gt;sort array($ array port,$ sortype,$ arraysize)输出结果如下:
0 = A 1 = B 2 = C 3 = f简化了可调用语法。Callable是可以被调用的PHP表达式,比如实例方法、静态方法或者可调用对象。例如,callable可用于创建方法调用的简短表达式。在PHP 8.1中,您可以使用新的可调用语法:
ariableCallableExpression(…)
ariableCallableExpression表示变量可调用表达式。省略号…包含在语法中。
为什么使用新的可调用语法?让我们通过一些例子来回顾一下传统的可调用语法是什么样子的:$ f1 = & # 39斯特兰& # 39;(…);$f2 = [$someobj,& # 39;一些方法& # 39;](…);$f3 = [SomeClass::class,& # 39;somestaticmethod & # 39](…);有两个问题:
语法涉及字符串和数组在创建可调用时,作用域不会被维护。为了演示这一点,请考虑如下用于对数组进行排序的脚本,其中 getSortArrayMethod() 方法返回 sortArray() 方法的可调用项,[$this,'sortArray'] 。
& lt?php类Sort { private array $ arrayToSort私有字符串$ sortTypepublic function _ _ construct($ arrayToSort,$ sort type){ $ this-& gt;arrayToSort = $ arrayToSort$ this-& gt;sortType = $ sortType}公共函数getSortArrayMethod(){ return[$ this,& # 39;有点儿像& # 39;];}私有函数sort array(){ if($ this-& gt;sortType = = & # 34Asc & # 34){ sort($ this-& gt;array sort);foreach($ this-& gt;arrayToSort as $ key = & gt$ val){ echo & # 34;$ key = $ val & # 34;} } else if($ this-& gt;sortType = = & # 34desc & # 34;){ rsort($ this-& gt;array sort);foreach($ this-& gt;arrayToSort as $ key = & gt$ val){ echo & # 34;$ key = $ val & # 34;} } else { shuffle($ this-& gt;array sort);foreach($ this-& gt;arrayToSort as $ key = & gt$ val){ echo & # 34;$ key = $ val & # 34;} } } } $ sortType = & # 34Asc & # 34;$ arrayToSort = array(& # 34;B&第34名;, "一& # 34;, "f & # 34, "C & # 34);$sort = new Sort($arrayToSort,$ Sort type);$ c = $ sort-& gt;getSortArrayMethod();$ c();该脚本生成以下错误消息:
致命错误:未捕捉到错误:使用closure:: from callable ([$ this,& # 39;有点儿像& # 39;])而不是[$this,& # 39;有点儿像& # 39;]可以解决范围问题,但是使用Closure::fromCallable方法会使调用变得冗长。新的可调用语法解决了长范围和语法的问题。使用新的可调用语法,函数变成:
公共函数getSortArrayMethod(){ return $ this-& gt;有点像(…);}数组按输出排序:
0 = A 1 = B 2 = C 3 = f新文法可以与涉及字符串和数组的传统文法结合起来解决作用域问题。创建可调用范围将保持不变。
公共函数getSortArrayMethod(){ return[$ this,& # 39;有点儿像& # 39;](…);新的可调用语法也可以用于静态方法,如下面的脚本所示,其中包含一个静态函数。
& lt?php类Sort { private array $ arrayToSort私有字符串$ sortTypepublic function _ _ construct($ arrayToSort,$ sort type){ $ this-& gt;arrayToSort = $ arrayToSort$ this-& gt;sortType = $ sortType}公共函数getStaticMethod(){ return Sort::aStaticFunction(…);}私有静态函数aStaticFunction(){ } } $ sort type = & # 34;Asc & # 34;$ arrayToSort = array(& # 34;B&第34名;, "一& # 34;, "f & # 34, "C & # 34);$sort = new Sort($arrayToSort,$ Sort type);$ cStatic = $ sort-& gt;getstatic method();$ cStatic();输出与之前相同:
0 = A 1 = B 2 = C 3 =下面是调用方法的等效方法:
return $ this-& gt;有点像(…);return Closure::from callable([$ this,& # 39;有点儿像& # 39;]);return [$this,& # 39;有点儿像& # 39;](…);下面是调用静态方法的等效方法:
返回Sort::aStaticFunction(…);return [Sort::class,& # 39;静态函数& # 39;](…);返回Closure::from callable([Sort::class,& # 39;静态函数& # 39;]);即使函数声明了形参,也可以使用新的可调用语法。
& lt?php类Sort { private array $ arrayToSort私有字符串$ sortTypepublic function _ _ construct($ arrayToSort,$ sort type){ $ this-& gt;arrayToSort = $ arrayToSort$ this-& gt;sortType = $ sortType}公共函数getSortArrayMethod(){ return $ this-& gt;有点像(…);}私有函数sortArray(int $a,string $ b){ if($ this-& gt;sortType = = & # 34Asc & # 34){ sort($ this-& gt;array sort);foreach($ this-& gt;arrayToSort as $ key = & gt$ val){ echo & # 34;$ key = $ val & # 34;} } else if($ this-& gt;sortType = = & # 34desc & # 34;){ rsort($ this-& gt;array sort);foreach($ this-& gt;arrayToSort as $ key = & gt$ val){ echo & # 34;$ key = $ val & # 34;} } else { shuffle($ this-& gt;array sort);foreach($ this-& gt;arrayToSort as $ key = & gt$ val){ echo & # 34;$ key = $ val & # 34;}}}如果一个方法声明了任何参数,就必须用它的参数来调用可调用对象。
$ sortType = & # 34Asc & # 34;$ arrayToSort = array(& # 34;B&第34名;, "一& # 34;, "f & # 34, "C & # 34);$sort = new Sort($arrayToSort,$ Sort type);$ c = $ sort-& gt;getSortArrayMethod();$c(1,& # 34;一& # 34;);简化语法可用于任何PHP可调用表达式,简化可调用语法可用于任何PHP可调用表达式。用于对象创建的new运算符不支持可调用语法,因为可调用语法ariableCallableExpression(…)不指定构造函数参数,这可能是必需的。不支持以下示例:
$sort =新排序(…);
生成的错误消息是:
致命错误:无法为新表达式创建闭包。以下脚本演示了所有支持的可调用表达式。
& lt?php类Sort { private array $ arrayToSort私有字符串$ sortTypepublic function _ _ construct($ arrayToSort,$ sort type){ $ this-& gt;arrayToSort = $ arrayToSort$ this-& gt;sortType = $ sortType}公共函数getSortArrayMethod(){ return $ this-& gt;有点像(…);}公共函数getStaticMethod(){ return Sort::aStaticFunction(…);}公共静态函数aStaticFunction() { }公共函数sortArray(int $a,string $ b){ if($ this-& gt;sortType = = & # 34Asc & # 34){ sort($ this-& gt;array sort);foreach($ this-& gt;arrayToSort as $ key = & gt$ val){ echo & # 34;$ key = $ val & # 34;} } else if($ this-& gt;sortType = = & # 34desc & # 34;){ rsort($ this-& gt;array sort);foreach($ this-& gt;arrayToSort as $ key = & gt$ val){ echo & # 34;$ key = $ val & # 34;} } else { shuffle($ this-& gt;array sort);foreach($ this-& gt;arrayToSort as $ key = & gt$ val){ echo & # 34;$ key = $ val & # 34;} } } public function _ _ invoke(){ } } $ sort type = & # 34;Asc & # 34;$ arrayToSort = array(& # 34;B&第34名;, "一& # 34;, "f & # 34, "C & # 34);$ classStr = & # 39排序& # 39;;$ staticmethodStr = & # 39静态函数& # 39;;$ C1 = $ class str::$ static method str(…);$ methodStr = & # 39有点儿像& # 39;;$sort = new Sort($arrayToSort,$ Sort type);$c2 = strlen(…);$c3 = $sort(…);//可调用对象$ C4 = $ sort->;有点像(…);$ C5 = $ sort-& gt;$methodStr(…);$c6 = Sort::aStaticFunction(…);$ C7 = $ class str::$ static method str(…);//传统的可调用字符串,数组$ c8 = & # 39斯特兰& # 39;(…);$c9 = [$sort,& # 39;有点儿像& # 39;](…);$c10 = [Sort::class,& # 39;静态函数& # 39;](…);$ c11 = $ sort-& gt;getSortArrayMethod();$c11(1,& # 34;一& # 34;);$ cStatic = $ sort-& gt;getstatic method();$ cStatic();尾逗号和可选/必需的参数顺序PHP 8.0的另一个新特性是,它支持在函数的参数列表末尾添加尾逗号,以提高可读性。任何尾随逗号都将被忽略。尾随逗号可能并不总是有用的,但是如果参数列表很长或者参数名称很长,它可能是有用的,因此您可以垂直列出它们。闭包用法列表也支持尾随逗号。
PHP 8.0不支持在必需参数前声明可选参数。在必需参数之前声明的可选参数是隐式必需参数。
以下脚本演示了必需参数的隐式顺序以及尾随逗号的使用。
& lt?php函数trailing _ comma _ example($the _ very _ first _ arg _ of _ this _ function,$the _ second _ arg _ of _ this _ function,$the _ this _ function _ fourth _ arg _ of _ this _ function,the _ last _ arg _ of _ this _ function),{ echo$the _ this _ function;} trailing_comma_example(1,2,null,3,4)?& gt输出如下所示:
已弃用(不推荐):在必需参数$the_last_arg_of_this_function之前声明的可选参数$ the _ this _ function将被隐式视为必需参数
。
参数Ke 空不是可选参数,但可以在必需参数之前以$param=null或显式Ke 空的形式声明。脚本如下:
& lt?php class A {}函数fn1(A $a = null,$b) {}函数fn2(?A $a,$b) {} fn1(新A,1);fn2(空,1);?& gt命名函数参数和自变量PHP 8.0不仅支持位置参数和自变量,还增加了对命名函数参数和自变量的支持。函数调用中命名参数的传输语法如下:
参数名称:参数值
命名参数的一些好处如下:
可以为函数参数指定一个有意义的名称,使它们能够自我记录按名称传递时,参数与顺序无关可以任意跳过默认值。在下面的脚本中, array_hashtable 函数声明了命名参数。 该函数传递的实参值可以带参数名,也可以不带参数名。当传递位置实参时,使用函数形参声明顺序。但传递命名实参时,可以使用任意顺序。
& lt?PHP function array _ hashtable($ key 1,$key2,$key3,$key4,$key5){ echo $key1。''。$key2。''。$key3。''。$key4。''。$ key5回声& # 34;& ltbr & gt";}//使用位置参数:array_hashtable(0,10,50,20,25);//使用命名参数:array _ hashtable (key 2: 0,key 5: 25,key 1: 10,key 4: 50,key 3:20);?& gt
输出结果是:
0 10 50 20 25
命名参数和位置参数可以在同一个函数调用中使用。对同一个示例函数array_hashtable使用混合参数调用。
& lt?PHP function array _ hashtable($ key 1,$key2,$key3,$key4,$key5){ echo $key1。''。$key2。''。$key3。''。$key4。''。$ key5回声& # 34;& ltbr & gt";}//使用混合参数:array _ hashtable (0,10,50,key 5: 25,key 4:20);?& gt输出结果是:
0 10 50 20 25
请注意,命名参数只能在位置参数之后使用。以下脚本颠倒了顺序,并在命名参数后使用位置参数:
& lt?PHP function array _ hashtable($ key 1,$key2,$key3,$key4,$key5){ echo $key1。''。$key2。''。$key3。''。$key4。''。$ key5回声& # 34;& ltbr & gt";}//使用混合参数:array_hashtable(0,10,key3: 25,50,key 5:20);?& gt该脚本生成的错误消息是:
致命错误:不能在命名参数
后使用位置参数
即使使用了命名参数,也不建议在必需参数之前声明可选参数。脚本如下:
& lt?PHP function array _ hashtable($ key 1 = 0,$key2=10,$key3=20,$key4,$key5){ echo $key1。''。$key2。''。$key3。''。$key4。''。$ key5回声& # 34;& ltbr & gt";}//使用混合参数:array _ hashtable (1,2,3: 25,4: 1,5:20);?& gt输出将包括不推荐(不推荐)的信息:
丢弃(不推荐):在必需参数$key5之前声明的可选参数$key1被隐式视为必需参数已弃用(不推荐):在必需参数$key5之前声明的可选参数$key2被隐式视为必需参数已弃用(不推荐):在必需参数$key5之前声明的可选参数$key3在必需参数之后使用可选命名形状时被隐式视为必需参数。
& lt?PHP function array _ hashtable($ key 1,$key2,$key3=20,$key4=50,$key5=10){ echo $key1。''。$key2。''。$key3。''。$key4。''。$ key5回声& # 34;& ltbr & gt";}//使用混合参数:array _ hashtable (key 1: 1,key 2: 2,key 4:25);?& gt输出结果是:
1 2 20 25 10
您可以只使用可选参数的子集来调用函数,而不考虑它们的顺序。
& lt?PHP function array _ hashtable($ key 1 = 0,$key2=10,$key3=20,$key4=50,$key5=10){ echo $key1。''。$key2。''。$key3。''。$key4。''。$ key5回声& # 34;& ltbr & gt";}//使用混合参数:array_hashtable(1,2,key 4:25);?& gt输出如下所示:
1 2 20 25 10
即使使用可选参数的子集调用函数,也不能在命名参数后使用位置参数。脚本如下:
& lt?PHP function array _ hashtable($ key 1 = 0,$key2=10,$key3=20,$key4=50,$key5=10){ echo $key1。''。$key2。''。$key3。''。$key4。''。$ key5回声& # 34;& ltbr & gt";}//使用混合参数:array_hashtable(1,2,key4: 25,5);?& gt生成的错误消息如下:
致命错误:不能在命名参数后使用位置参数PHP 8.1,提高了命名参数的特性,支持解包参数后的命名参数。脚本如下:
& lt?PHP function array _ hashtable($ key 1,$key2,$key3=30,$key4=40,$key5=50){ echo $key1。''。$key2。''。$key3。''。$key4。''。$ key5回声& # 34;& ltbr & gt";}echo array_hashtable(…[10,20],key 5:40);echo array_hashtable(…['key2 & # 39= & gt2, 'key1 & # 39= & gt2],key 4:50);?& gt
输出如下所示:
10 20 30 40 402 2 30 50 50但是,命名参数不能覆盖前面的参数。脚本如下:
& lt?PHP function array _ hashtable($ key 1,$key2,$key3=30,$key4=40,$key5=50){ echo $key1。''。$key2。''。$key3。''。$key4。''。$ key5回声& # 34;& ltbr & gt";}echo array_hashtable(…[10,20],key 2:40);?& gt输出如下所示:
致命错误:未捕获错误:命名参数$key2覆盖了以前的参数。PHP 8.0之前不能静态调用非静态方法。如果在静态上下文中调用非静态方法,或者它们是静态调用的,您将只会收到一条不推荐使用的消息。在8.0中,您现在会收到一条错误消息。另外,$this在静态上下文中是未定义的。为了演示这一点,请考虑下面的脚本,其中使用静态语法A::aNonStaticMethod()调用了非静态方法aNonStaticMethod()。
& lt?phpclass A { function anonstatic method(){ } } A::anonstatic method();如果您运行此脚本,您将收到以下错误消息:
未捕捉到错误:不能静态调用非静态方法A::aNonStaticMethod()。PHP 8.1支持纤程多任务。纤程是一个有自己堆栈的可中断函数。纤程可以从调用堆栈中的任何地方挂起,然后再恢复。新的纤程类是最终类,它支持以下公共方法:
方法
形容
_ _构造(callable $ callback)& lt;br & gt
为新的纤程实例创建构造函数。这个参数是一个可调用的对象,当纤程启动时被调用。提供给Fiber::start()的参数将作为给定可调用对象的参数提供。可调用对象根本不需要调用Fiber::suspend(),或者即使调用,也不需要直接调用。对Fiber::suspend()的调用可能深深地嵌套在调用堆栈中。
开始(混合…$args):混合
开始纤维。当纤程挂起或终止时,此方法返回。当构造纤程时,为所使用的可调用函数提供了一个可变参数列表。如果返回纤程,则从第一个挂点返回混合值或NULL。如果调用此方法时纤程已经启动,将抛出FiberError错误。
resume(mixed $value = null):混合
从Fiber::suspend()中恢复纤程并返回给定的混合值。当纤程挂起或终止时返回。返回的混合值实际上是从下一个悬挂起点返回的,如果返回纤程则返回NULL。如果纤程没有启动、运行或终止,就会抛出FiberError错误。
throw(Throwable $exception):混合
将给定的异常从Fiber::suspend()抛出到纤程中。当纤程挂起或终止时返回。该参数是Throwable $exception。返回的混合值实际上是从下一个悬挂起点返回的,如果返回纤程则返回NULL。如果纤程没有启动、运行或终止,就会抛出FiberError错误。
getReturn():混合
获取纤程回调的混合返回值。如果纤程不返回语句,则返回NULL。如果纤程没有被终止或者纤程抛出异常,那么抛出FiberError错误。
isStarted(): bool
如果纤程已经启动,则返回布尔值True。
isSuspended(): bool
如果纤程被挂起,则返回布尔值True。
isRunning(): bool
如果纤程正在运行,则返回布尔值True。
isTerminated(): bool
如果纤程已经终止,则返回布尔值True。
静态挂起(mixed $value = null):混合
挂光纤。返回到光纤-& gt;start()、Fiber-& gt;简历()或纤维->;调用throw()的执行。可以使用Fiber::resume()或Fiber::throw()来恢复纤程。不能从纤程外的主线程调用。参数是从Fiber::resume()或Fiber::throw()返回的混合值$value。返回的混合值被提供给Fiber::resume()。& ltbr & gt如果它不在纤程中(也就是说,如果它是从主线程调用的),就会抛出FiberError错误。
静态getCurrent():?纤维
返回当前正在执行的纤程实例,如果它在主线程中,则返回NULL。
纤程只能启动一次,但可以暂停和恢复多次。以下脚本通过使用纤程对数组执行不同类型的排序来演示多任务处理。纤维在每次分类后都会挂起,然后继续不同的分类。
& lt?PHP $ Fiber = new Fiber(function(array $ arr):void { sort($ arr);foreach($ arr as $ key = & gt;$ val){ echo & # 34;$ key = $ val & # 34;} echo & # 34& ltbr/>;";fiber::suspend();rsort($ arr);foreach($ arr as $ key = & gt;$ val){ echo & # 34;$ key = $ val & # 34;} echo & # 34& ltbr/>;";fiber::suspend();洗牌($ arr);foreach($ arr as $ key = & gt;$ val){ echo & # 34;$ key = $ val & # 34;} });$ arrayToSort = array(& # 34;B&第34名;, "一& # 34;, "f & # 34, "C & # 34);$ value = $ fiber-& gt;start($ array sort);$ fiber->;resume();$ fiber->;resume();?& gt
输出如下所示:
0 = A 1 = B 2 = C 3 = F0 = F 1 = C 2 = B 3 = A0 = C 1 = F 2 = A 3 = B如果纤程在第一次挂起后没有恢复,那么只会执行一种类型的排序,这可以通过注释掉两个resume()调用来实现。
//$ fiber-& gt;resume();//$ fiber-& gt;resume();输出是第一次排序的结果:
0 = A 1 = B 2 = C 3 = fStringable接口和__toString()PHP 8.0引入了一个名为Stringable的新接口,它只提供了一个方法__toString()。__toString()方法(如果在类中提供)隐式实现Stringable接口。考虑提供__toString()方法的类A。
& lt?PHP class A { public function _ _ toString():string { return & # 34;";} } echo(new A()instance of Stringable);
该脚本从Stringable的类型检查中返回1。
然而,事实恰恰相反。如果该类实现Stringable接口,则必须显式提供__toString()方法,因为它不会自动添加,例如:
& lt?Php class a实现string { public function _ _ tostring():string { } }新的标准库函数PHP 8引入了许多属于其标准库的新函数。
str_contains函数返回一个bool值,指示作为第一个参数的字符串是否包含作为第二个参数的字符串。以下脚本将返回false:
& lt?phpif(str _ contains(& # 39;干草堆& # 39;, '针& # 39;)){ echo true} else { echo false}以下脚本返回1或true:
& lt?phpif(str _ contains(& # 39;干草堆& # 39;, '干草& # 39;)){ echo true} else { echo & # 34假& # 34;;str _ starts _ with函数返回一个bool值,指示字符串是否作为第一个参数}str_starts_with字符串作为第二个参数。以下脚本将返回false。
& lt?phpif(str _ contains(& # 39;干草堆& # 39;, '干草& # 39;)){ echo true} else { echo & # 34假& # 34;;}
以下脚本返回1或true。
& lt?phpif(str _ starts _ with(& # 39;干草堆& # 39;, '针& # 39;)){ echo true} else { echo false}
str_ends_with函数返回一个bool值,指示作为第一个参数的字符串是否以作为第二个参数的字符串结尾。以下脚本将返回false。
& lt?phpif(str _ starts _ with(& # 39;干草堆& # 39;, '针& # 39;)){ echo true} else { echo false}以下脚本将返回1,或true。
& lt?phpif(str _ starts _ with(& # 39;干草堆& # 39;, '干草& # 39;)){ echo true} else { echo false}fdiv函数将两个数相除并返回一个浮点值。脚本如下:
& lt?phpvar_dump(fdiv(1.5,1.3));var_dump(fdiv(10,2));var_dump(fdiv(5.0,0.0));var_dump(fdiv(-2.0,0.0));var_dump(fdiv(0.0,0.0));var_dump(fdiv(5.0,1.0));var_dump(fdiv(10.0,2));输出是:
浮动浮动浮动浮动浮动浮动浮动浮动浮动浮动
fdatasync函数(在Windows上的别名是fsync)用于将数据同步到文件流中。为了演示它的用法,在包含要运行的PHP脚本的脚本目录中创建一个空文件test.txt。运行脚本:
& lt?php $ file = & # 39test.txt & # 39;$stream = fopen($file,& # 39;w & # 39);fwrite($stream,& # 39;第一行数据& # 39;);fwrite($stream,& # 34;\\ r \\ n & # 34);fwrite($stream,& # 39;第二行数据& # 39;);fwrite($stream,& # 39;第三行数据& # 39;);fdatasync($ stream);fclose($ stream);随后,当您打开test.txt文件时,您会发现它包含以下文本:
第一行数据第二行数据第三行数据
函数的作用是:返回一个布尔值,表明给定的数组是否是一个列表。数组必须以0开始,并且键必须是顺序正确的连续整数。以下脚本演示了array_is_list函数:
& lt?phpecho array _ is _ list([]);echo array _ is _ list([& # 39;1', 2, 3]);echo array _ is _ list([0 = & gt;'一& # 39;, 'b & # 39]);echo array _ is _ list([1 = & gt;'一& # 39;, 'b & # 39]);//false echo array _ is _ list([1 = & gt;'一& # 39;,0 = & gt'b & # 39]);//false echo array _ is _ list([0 = & gt;'一& # 39;, 'b & # 39= & gt'b & # 39]);//false echo array _ is _ list([0 = & gt;'一& # 39;,2 = & gt'b & # 39]);// false
输出是:
魔术方法必须有正确的签名。魔术方法是一种特殊的方法,用于覆盖PHP中的默认操作。它们包括以下方法,其中最常见的可能是构造函数__construct()。
__construct()、__destruct()、__call()、__callStatic()、__get()、__set()、__isset()、__unset()、__sleep()、__wakeup()、__serialize()、_ _ tostring()、_ _ invoke()、_ _ set _ state()、_ _ clone()、_ _ debuginfo()从PHP 8.0开始,魔术方法定义的签名必须正确,这意味着如果在方法参数或new __toString()方法的返回类型必须声明为String。下面的演示将返回类型声明为int:
& lt?PHP class a { public function _ _ tostring():int { } }将生成以下错误消息:
致命错误:A::__toString():声明时返回类型必须是字符串。但是,根据定义不声明返回类型的函数(如构造函数)不能声明返回类型,即使它是void。以下脚本中显示了一个示例:
& lt?PHP class a { public function _ _ construct():void { } }这个脚本将返回以下错误消息:
致命错误:方法A::__construct()不能声明返回类型的所有魔术方法,只有少数例外(如__construct()),必须声明为公共可见性。为了演示这一点,声明了一个具有私有可见性的__callStatic。
& lt?PHP class a { private static function _ _ callstatic(string $ name,array $ arguments) {}}输出的警告消息是:
警告:魔法方法A::__callStatic()必须具有公共可见性。尽管可以省略混合返回类型,但方法签名必须相同。例如,在下面的脚本中,类A声明__callStatic而不指定其返回类型,而类B将其第一个参数定义为int:
& lt?PHP class a { public static function _ _ callstatic(string $ name,array $ arguments){ } class b { public static function _ _ callstatic(int $ name,array $ arguments) {}}输出的错误消息如下:
致命错误:B::__callStatic():参数#1 ($name)必须声明为字符串类型。与内部类的兼容性在PHP 8.1中,大部分内部方法,也就是内部类中的方法,已经开始“暂定”声明返回类型。初步建议,虽然在8.1版本中,只会触发推荐通知,但在9.0版本中,会输出错误条件信息。因此,任何扩展类都必须声明一个与内部类兼容的返回类型,否则将引发一个不推荐使用的通知。为了演示这一点,扩展内部类目录并重新声明函数read()而不返回类型:
& lt?Php class a扩展目录{public function read () {}}这个脚本将生成一个不推荐使用的通知:
& lt?phpclass A扩展目录{ public function read():string { return & # 34;";}}但是,以下脚本是可能的:
& lt?phpclass A扩展目录{ public function read():string { return & # 34;";}}添加#[\\ReturnTypeWillChange]属性可以禁止不推荐使用的通知:
& lt?PHP class a extends directory { #[\\ returntype will change]public function read(){ } } \\ sensitive parameter属性虽然包含方法参数详细信息的异常堆栈跟踪对于调试非常有用,但是您可能不希望输出一些敏感参数的参数值,例如与密码和凭据相关的参数值。PHP 8.2引入了一个名为\\SensitiveParameter的新属性,这样如果方法的参数用\\ SensitiveParameter属性注释,参数的值就不会在异常堆栈跟踪中输出。
为了演示这一点,考虑以下脚本,其中函数f1具有与\\SensitiveParameter属性相关联的参数$password。
& lt?php函数f1( $param1 = 1,#[\\ sensitive parameter]$ password = \” s @ 5f _ u7 \”,$ param 3 = null){ throw new \\ Exception(& # 39;错误& # 39;);}为了演示\\SensitiveParameter特性,这个函数只是抛出一个异常。呼叫功能:
f1(参数3:& # 39;一& # 39;);请注意,异常堆栈跟踪不包含$password参数的值,但列出了对象(SensitiveParameterValue)。
堆栈跟踪:#0 : f1(1,Object(SensitiveParameterValue),& # 39;一& # 39;)#1 {main}内置函数弃用/增强内置函数utf8_encode()和utf8_decode()经常被人误解,因为它们的名字都意味着编码/解码任意字符串。事实上,这些函数仅用于编码/解码ISO8859-1,即“拉丁-1”字符串。此外,它们生成的错误消息对于调试来说不够详细。PHP 8.2已经弃用了这些函数。以下脚本使用了它们:
& lt?php $ string _ to _ encode = & # 34\\ x7A \\ x6A \\ xdB & # 34;$ utf8 _ string = utf8 _ encode($ string _ to _ encode);echo bin2hex($utf8_string),& # 34;\\ n & # 34;$ utf8 _ string = & # 34\\ x6A \\ x6B \\ xD3 \\ xCB & # 34;$ decoded _ string = utf8 _ decode($ utf8 _ string);echo bin2hex($decoded_string),& # 34;\\ n & # 34;对于PHP 8.2,会输出一个不推荐使用的通知:
已弃用(不推荐):函数utf8_encode()已弃用(不推荐):函数utf8_decode()在PHP 8.2中已弃用,函数iterator_count和iterator_to_array接受所有可迭代对象。函数的作用是:将迭代器的元素复制到一个数组中。iterator_count()函数计算数组的元素个数。这些函数接受$iterator作为第一个参数。在PHP 8.2中,$iterator参数的类型已经从Trersable扩展到Trersable|array,以接受任意迭代值。
以下脚本演示了它们在数组和可遍历对象中的用法。
& lt?PHP $ a = array(& # 39;1'= & gt'一& # 39;, '两& # 39;, '三& # 39;, '四& # 39;);$ iterator = new array iterator($ a);var _ dump(iterator _ to _ array($ iterator,true));var_dump(iterator_to_array($a,true));var _ dump(iterator _ count($ iterator));var _ dump(iterator _ count($ a));输出如下所示:
array(4) { [1]= >字符串(3)& # 34;一& # 34;[2]= >字符串(3)& # 34;两& # 34;[3]= >字符串(5)& # 34;三& # 34;[4]= >字符串(4)& # 34;四& # 34;} array(4){[1]= & gt;字符串(3)& # 34;一& # 34;[2]= >字符串(3)& # 34;两& # 34;[3]= >字符串(5)& # 34;三& # 34;[4]= >字符串(4)& # 34;四& # 34;} int(4) int(4)总结在这一系列PHP 8文章中,我们已经讨论了与函数和方法相关的新特性,其中最突出的是命名函数的形式参数/实参、简化的可调用语法和称为纤程的可中断函数。
在本系列的下一篇文章中,我们将介绍PHP类型系统的新特性。
原始链接:
https://www.infoq.com/articles/php8-functions-methods/
相关阅读:
PHP 8:注释、匹配表达式和其他改进
PHP 8:类和片段
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。