本文要点
要在运行时创建命名的数组常量,我们可以使用新的
define()
函数。要将对象作用域绑定到一个变量并调用它,我们可以使用新的
Closure::call()
函数。要通过传统的
assert()
使用表达式和/或自定义AssertionError
,那么我们可以使用 expectation。PHP 7 支持从 Generator 函数返回一个值。
PHP 7 支持将一个 Generator 函数委托给另一个 Generator 函数。
对于整数除法,使用名为
intdiv()
的新函数。要覆盖
php.ini
中的会话配置的设置,可以使用新的session_start
函数。要使用回调执行正则表达式搜索和替换,使用新的函数
preg_replace_callback_array()
。PHP 7 能够生成加密安全的整数和字节。
PHP 7.1 支持将回调转换为闭包。
箭头(=>)函数为匿名函数提供了简洁的语法。
在PHP 7系列前面的文章中,我们讨论了 PHP 类型系统的新特性。在本文中,我们将会探讨 PHP 7 在函数方面的改善。
PHP 支持多种类型的函数,包括用户自定义函数、内部函数、变量函数以及匿名函数。
定义数组常量的新函数
PHP 7.0 添加了名为define()
的新函数,用来在运行时定义命名的数组常量。define()的语法如下所示:
bool define ( string $name , mixed $value [, bool $case_insensitive = FALSE ] )
</pre>
表 1 讨论了该函数的参数
<small>表 1 define()函数的参数</small>
创建 PHP 脚本_constant.php_并定义名为CONSTANT
的常量,如下所示。
define("CONSTANT", "Hello PHP");
我们还可以使用const
关键字来定义常量:
define()
函数可以用来定义数组常量:
define("Catalog", ['Oracle Magazine','Java Magazine']);
数组常量的值可以使用数组元素访问的方式进行输出。
_constant.php_文件如下所示:
运行脚本将会输出脚本中定义的常量值。
全局定义的常量,如TRUE
或FALSE
,不能进行重定义。为了阐述这一点,我们创建一个_const.php_脚本,该脚本定义了常量TRUE
,并将它的值设置成了20
:
如果你运行该脚本的话,它将会输出的值是1
,这也是TRUE
全局定义的值。
绑定对象作用域到闭包的新函数
闭包是用来表示匿名函数的类。PHP 7.0 引入了新的Closure::call()
函数,能够非常简便地将对象作用域临时绑定到一个闭包并调用它。为了阐述这一点,创建脚本_closure.php_并复制如下清单所示的代码:
在上述脚本中,Hello 是一个具有函数getMsg()
的类。Closure::call()
函数用来创建一个Hello
实例,并绑定它的作用域到一个调用getMsg
方法的闭包。运行该脚本将会输出Hello
消息。
Expectation
在讨论_expectation_之前,我们先看一下传统的断言。传统的assert()
方法定义如下所示。它会检查如果代码的预期值(称为_断言_)是不是为FALSE
,如果是FALSE
的话,它会打印出描述消息,并且默认会中止程序。如果断言不是FALSE
的话,assert()
没有任何效果。
bool assert ( mixed $assertion [, string $description ] )
按照设计,断言用于开发和测试期的调试,而不是运行期的操作。assert()
的行为可以通过assert_options()或者.ini
文件进行配置。
传统上,assert()
的第一个参数应该是一个要评估计算的字符串或者作为断言进行测试的 boolean 条件。如果所提供的是一个字符串的话,它会以 PHP 代码的形式进行评估计算。如果所提供的是一个 boolean 条件的话,那么在传递给assert_options()
定义的断言回调函数(如果存在的话)之前,它将会被转换成字符串。
断言在 PHP 7 中进行了彻底修改,现在被称为_expectation_,并且assert()
是 PHP 7 中的一个语言结构。作为对assert()
的增强,expectations 被添加了进来,并且具有如下的语法:
bool assert ( mixed $assertion [, Throwable $exception ] )
有了 expectations 之后,assert()
的第一个参数可能是会返回一个值的表达式,而不再是一个要评估执行的 PHP 代码字符串或者要测试的 boolean 条件。表达式会被执行,得到的结果会被用来确定断言是否成功。从 PHP 7 开始,使用字符串作为第一个参数已经被废弃掉了。assert_options()
依然能够与 expectations 协同使用,但是并不推荐这么做。相反,我们应该使用两个新的 php.ini 配置指令,如表 2 所示。
<small>表 2 Expectations 的配置指令</small>
借助 expectations,第二个参数可能会是一个Throwable
对象,而不再是字符串描述。为了在断言失败的时候抛出Throwable
对象或异常,assert.exception
指令必须设置为 1。
相对于传统的断言,expectations 有如下的优势,不过为了向后兼容,传统的断言依然是支持的:
可以用表达式来评估一个断言,而不是字符串或 boolean 值。
通过使用
php.ini
设置,断言代码即便已经生成,但可以在运行期跳过它们。甚至可能根本就不生成断言代码,对于生产环境的使用来说,推荐这样做。可以抛出自定义异常。PHP 7 新增加了类
AssertionError
。
作为如何使用 expectations 的样例,我们创建一个名为_expectation.php_的脚本,并复制如下的代码清单到脚本中。这个脚本将这两个配置指令都设置成了 1。assert
语言结构将第一个参数设置为 true,第二个参数设置为一个自定义的AssertionError
。
如果运行这个脚本的话,将不会抛出AssertionError
。
接下来,将第一个参数设置为false
。
assert(false, new AssertionError('Assertion failed.'));
如果再次运行脚本的话,expectation 将会失败并抛出AssertonError
。
Uncaught AssertionError: Assertion failed
为了阐述在assert()
中借助表达式和自定义AssertionError
使用 expectations,我们首先从传统的使用assert()
方式开始,测试一个变量是数字的断言。这里使用字符串来测试变量,并在断言失败的时候输出消息。
接下来,使用表达式作为assert()
的第一个参数。然后,使用AssertionError
对象来抛出自定义的错误信息。
Generator 支持 return 表达式
Generator 函数是能够返回一个迭代对象的函数,比如foreach
。Generator 函数是简单的迭代器,它们不需要类实现Iterator
接口。Generator 函数的语法与普通函数的语法一样,只不过函数中包含一个或多个yield
语句,当 Generator 函数所返回的迭代器被迭代的时候,每个 yield 语句都会生成一个值。Generator 函数必须要像正常的函数那样进行调用,并提供所有必要的参数。
PHP 7.0 为 Generator 函数添加了一个新的特性,那就是支持在所有的 yield 语句之后声明一个 return 语句。在 Generator 函数中所返回的值可以通过 Generator 函数返回对象的getReturn()
函数来进行访问。我们不要将 Generator 函数返回的迭代器对象与 Generator 函数返回的值混淆。迭代器对象并不包含返回值,它只包含 yield 所生成的值。如果 Generator 函数需要执行某些计算并返回一个最终值的话,那么能够返回值就是非常有用的。Generators 可以声明Generator
、Iterator
、Traversable
或iterable
返回类型。
为了阐述如何使用这个新特性,我们创建名为 gen_return.php 的脚本,该脚本定义了带有多个 yield 语句的 Generator 函数并且在调用 Generator 函数的时候传入1
作为参数。接下来,使用 foreach 迭代它的返回值并输出 yield 所生成的值。最后,使用getReturn()
函数输出返回值。gen_return.php 脚本如下所示:
如果运行脚本的话,将会得到如下的输出:
1 3 5
Generator 委托
PHP 7.0 添加了对 Generator 委托的支持,这意味着一个 Generator 可以通过_yield from_关键字委托给另外一个 Generator、Traversable
对象或数组。为了阐述 Generator 委托功能,我们创建名为 gen_yield_from.php 的脚本并定义两个 Generator 函数,即gen($var)
和gen2($var)
,其中gen($var)
通过如下的语句委托给了gen2($var)
:
yield from gen2($var);
随后,在一个foreach
循环中遍历gen($var)
所返回的迭代器对象。脚本 gen_yield_from.php 如下所示:
运行脚本将会输出这两个 Generator 函数所生成的值:
1 3 1 2
整数除法的新函数
PHP 7.0 为整数除法添加了一个新函数intdiv()
。这个函数会返回一个整数,该整数代表了两个整数的商,它具有如下的语法。
int intdiv ( int $dividend , int $divisor )
创建名为 int_div.php 的脚本以使用intdiv()
函数,我们在这里添加一些整数除法的样例。像PHP_INT_MAX
和PHP_INT_MIN
这样的 PHP 常量可以用作该函数的参数。
如果运行脚本的话,将会得到如下所示的输出:
如果存在ArithmeticErrors
的话,它将会输出到浏览器中。为了阐述这一点,添加如下的函数调用并再次运行脚本。
var_dump(intdiv(PHP_INT_MIN, -1));
在本例中,将会生成一个ArithmeticError
表明PHP_INT_MIN
除以-1 的结果不是一个整数:
Uncaught ArithmeticError: Division of PHP_INT_MIN by -1 is not an integer
添加如下的函数调用到 int_div.php 脚本中并再次运行该脚本。
var_dump(intdiv(1, 0));
这次,将会抛出DivisionByZeroError
:
Uncaught DivisionByZeroError: Division by zero
新的会话选项
session_start
函数可以用来开始一个新的会话(session)或恢复一个之前已经存在的会话。PHP 7.0 添加了对名为options
的新参数的支持,该参数是一个相关选项的数组,它们可以覆盖php.ini
中的会话配置指令。在php.ini
中,这些会话配置指令均以session.
开头,但是在以函数入参的形式为session_start
提供 options 参数数组的时候,session.
前缀要省略。除了会话配置指令,还新增了一个read_and_close
选项,如果该选项设置为TRUE
,在读取之后,该会话会关闭,因为保持会话处于打开状态可能没有必要。作为样例,我们创建一个名为 session_start.php 的脚本并复制如下所示的代码清单。在样例脚本中,session_start(options)
函数调用通过数组设置了一些配置指令:
在运行脚本的时候,脚本中的会话配置选项将会覆盖掉php.ini
中所定义的会话配置指令(如果存在的话)。该脚本不会生成任何输出。
在 PHP 7.1 中,如果session_start()
开启会话失败的话,它将会返回FALSE
并且不会初始化$_SESSION
。
使用回调执行正则表达式搜索和替换的新函数
PHP 7.0 增加了一个新的函数preg_replace_callback_array()
,以便于使用回调进行正则表达式搜索和替换。这个函数与preg_replace_callback()
函数类似,只不过回调是基于每个模式调用的。函数的语法如下所示:
mixed preg_replace_callback_array ( array $patterns_and_callbacks , mixed $subject [, int $limit = -1 [, int &$count ]] )
如果$subject
参数是一个数组的话,它会返回一个字符串组成的数组,如果$subject
是字符串的话,它会返回一个字符串。如果匹配上了的话,那么返回的数组和字符串就是新的主题(subject),如果找不到匹配项的话,那么将会返回未改变的主题。该函数的参数如表 3 所示。
<small>表 3 preg_replace_callback_array 的函数参数</small>
为了阐述这个新的功能,创建样例脚本 prereg.php 并复制如下的代码清单到脚本中。主题或要搜索的样例字符串设置成了'AAaaaaa Bbbbb'。patterns_and_callbacks
参数设置成了寻找匹配'A'和'b'的数量。
如果运行脚本的话,匹配'A'和'b'的数量将会被打印出来:
7 matches for "A" found 5 matches for "b" found
生成加密安全的整数和字节的新函数
新增了两个生成加密安全的整数和字节的新函数。这些函数在表 4 中进行了讨论。
<small>表 4 新的加密函数</small>
作为样例,我们创建一个名为 random_int.php 的脚本,它会生成加密的任意整数。首先,生成一个范围在 1 和 99 之间的整数,然后生成一个范围在-100 到 0 的整数。
如果运行脚本的话,将会打印出两个整数。
int(98) int(-84)
生成的整数是随机的,如果相同的脚本再次运行的话,很可能会生成两个不同的整数。
接下来,创建另外一个样例脚本 random_bytes.php,它会生成加密的任意字节,其长度为 10。然后,我们使用bin2hex
函数将任意的字节转换成 ASCII 字符串,其中包含了所返回字节的 16 进制字符串形式。复制如下的代码清单到脚本文件中:
运行脚本并生成加密的任意字节:
string(20) "ab9ad4234e7c6ceeb70d"
list()函数的修改
list()
函数用来为一个变量列表像数组那样进行赋值。PHP 7.0 和 7.1 为 list()带来了一些变更。在 PHP 7 中,list()
无法像之前的版本那样解包字符串,如果对字符串进行解包的话,将会返回NULL
。
在 PHP 5.x 中,使用list()
解包一个字符串的时候,会将list()
中的一个变量赋值为字符串中的值。我们使用 PHP 5.x 中的list()
来阐述解包字符串。创建脚本_list.php_并复制如下的代码清单到脚本中。
该脚本解包$str
中的一个值到一个列表元素中。使用 PHP 5.x 运行该脚本,$elem
的值会输出‘a’。如果你在 PHP 7.0 中再次运行该脚本的话,那么会输出NULL
。另外一个无法在 PHP 7 中解包字符串的list()
样例如下所示:
如果运行该脚本的话,与前面的脚本类似,我们会看到输出的值是NULL
。
实际上,在 PHP 7.x 中,如果list()
要通过字符串进行赋值,那么必须要使用str_split
函数:
如果运行上述样例的话,列表元素按照预期被设置成了‘a’。在 PHP 7.0 中,list()
表达式不能完全为空。作为样例,运行如下 list.php 程序清单:
这一次,会输出一条错误信息,表明“Cannot use empty list..”。列表中可以部分元素为空。在下面的代码清单中,list()
中的一个元素为空:
如果运行该脚本的话,不会生成错误,并且会创建一个具有两个非空元素和一个空元素的列表。
Oracle Magazine latest edition is January-February 2018.
list()
函数的另外一个修改就是按照变量定义的顺序为其进行赋值。在此之前,值是按照与定义相反的顺序进行赋值的。为了阐述之前的行为,使用 PHP 5.x 运行如下的 list.php 中的程序清单:
我们可以探测脚本的输出(参见图 1),值是按照定义相反的顺序进行赋值的。
图 1 值是按照相反的顺序赋值的
在 PHP 7.0 上运行相同的脚本,我们会发现_list()_会按照与定义相同的顺序为变量赋值:
array(3) { [0]=> string(1) "A" [1]=> int(2) [2]=> int(3) }
PHP 7.1.0 支持在列表中指定 key 以表明赋值的数字顺序。作为样例,创建 list.php 脚本并包含如下的代码清单。注意,在本例中,所有的 key 都是数字:
如果运行脚本的话,将会得到如下的列表值:
Oracle Magazine, Oracle Publishing, January February 2018.
赋值的数字顺序可以交叉,如下面的代码清单所示,索引 0 放在了索引 1 的后面。
如果运行脚本的话,输出的值表明变量是根据数字的 key 进行赋值的,而不是列表中 key 的顺序。
Oracle Publishing, Oracle Magazine,January February 2018
key 的索引可以使用单括号或双括号括起来,如下所示:
上述脚本会生成与前面的脚本相同的输出。如果在list()
中某个元素使用了 key,那么它的所有元素都应该使用 key。例如,创建一个列表,有些元素使用了 key 进行赋值,有些元素没有使用 key:
如果运行该脚本的话,我们会看到一个错误信息,提示在赋值的时候,带有 key 和不带 key 的数组条目不能混合使用:
Cannot mix keyed and unkeyed array entries in assignments
字符串偏移支持负数
从 PHP 7.1 开始,像strpos
和substr
这样的字符串操作函数引入了对负数偏移量的支持,也就是从字符串的结尾处开始处理偏移。使用[]和{}的字符串索引也支持负数偏移量。例如,"ABC"[-2]将会返回字母'B'。现在,我们创建一个脚本 str-negative-offset.php 并复制如下的代码清单到脚本中:
该脚本提供了多个在字符串函数和[]中使用负数偏移量的样例。如果运行脚本的话,它将会输出:
将回调转换成闭包的新函数
闭包用来以字符串变量的形式传递函数(用户自定义的函数以及除语言构造之外的内置函数)和方法。例如,函数hello()
可以以参数的形式传递给另外一个函数,或者使用函数名字以字符串的形式从另外一个函数中返回,如'hello',当然这样做的前提是参数类型/返回类型为 callable。我们创建一个样例脚本 callable.php 并声明函数hello()
,该函数输出一个‘hello’消息。声明另外函数,其参数类型是 callable。
callFunc(callable)
函数能够以字符串的形式通过hello()
的名字调用该函数:
callFunc("hello");
另外,内置的call_user_func ( callable $callback [, mixed $... ] )
函数以 callable 作为其第一个参数,也可以用来根据名字调用hello()
函数:
call_user_func('hello');
脚本_callable.php_如下所示:
如果运行脚本的话,会根据所提供的名称调用hello()
函数。
hello
hello
闭包是匿名函数的对象表示形式。那为什么要将回调转换成闭包呢?有多个原因,其中一个就是性能。回调类型相对比较慢,因为确定一个函数是否为回调需要一定的成本。
使用回调的另外一个缺点在于,只有 public 的函数可以用作回调。相反,将类中的函数转换成闭包并不需要该函数是 public 的,例如该函数可以声明为 private。作为样例,我们创建一个脚本_hello.php_并声明一个类Hello
,该类中包含返回一个回调函数的方法getCallback()
:
回调函数声明为 public。
public function hello_callback_function($name) { var_dump($name); }
创建该类的一个实例并调用回调函数。_hello.php_脚本如下所示:
如果运行脚本的话,会得到如下的输出:
string(6) "Deepak"
接下来,使用Closure::fromCallable
静态方法将私有的回调函数转换成一个闭包。
如果运行脚本的话,会得到相同的输出:
string(6) "Deepak"
转换成闭包的另外一个原因在于能够在早期探测到错误,不必推迟到运行期。考虑如上面所示的样例,但是这一次我们故意把函数名称拼错:
如果运行这个脚本的话,当回调函数在如下的语句实际执行的时候,将会抛出Call to undefined method Hello::hello_callback_functio()
错误:
$callback('Deepak');
相反,如果我们将回调转换成闭包,错误Failed to create closure from callable: class 'Hello' does not have a method 'hello_callback_function'
会在如下这行代码中就能探测出来:
return Closure::fromCallable([$this, 'hello_callback_functio']);
JSON_THROW_ON_ERROR 标记
在 PHP 7.3 版本之前,对 JSON 函数 json_encode()和 json_decode()的错误处理功能都是非常少的,有如下的不足之处:
如果出现错误的话,
json_decode()
会返回 null,但是 null 可能是一个合法的值,比如要对 JSON “null”进行解码。判断是否有错误出现的唯一办法是使用json_last_error()
或json_last_error_msg()
查看全局的错误状态。json_encode()
没有错误的返回值。出现错误的时候,程序的运行不会停止,甚至不会抛出警告。
PHP 7.3 在json_encode()
和json_decode()
方法中添加了对JSON_THROW_ON_ERROR
标记的支持。添加了新的异常子类JsonException
,用来描述 JSON 解码/编码。如果为json_encode()
和json_decode()
提供JSON_THROW_ON_ERROR
标记并抛出了 JsonException 异常的话,那么全局的错误状态不会被修改。为了阐述新的JSON_THROW_ON_ERROR
和JsonException
,我们创建一个_json.php_脚本,并尝试使用json_decode
解码一个包含错误的数组:
如果运行脚本的话,我们会看到如下所示的JsonException
:
Maximum stack depth exceeded
作为使用JSON_THROW_ON_ERROR
和json_encode()
的样例,我们编码一个数组,该数组中包含一个值为 NAN 的元素,如下面的程序清单所示:
当运行脚本的时候,会输出如下的信息:
Inf and NaN cannot be JSON encoded
从数组中获取第一个和最后一个 key 值的新函数
从数组中获取第一个和最后一个 key 值是很常见的操作,PHP 7.3 专门新加了两个函数:
如下的代码清单给出了在相关数组甚至空数组中使用这两个函数的样例:
脚本的输入如下所示:
使用 Compact 函数报告未定义的变量
compact()
函数在 PHP 7.3 中有一个新的特性,那就是报告未定义的变量。为了阐述该功能,运行如下的脚本,该脚本中包含了一些未定义的变量:
脚本将会输出如下的信息:
函数调用中的拖尾逗号
PHP 7.3 添加了在函数调用时使用拖尾逗号的支持。拖尾逗号在有些经常追加参数的场景中是很有用处的,比如可变参数的函数(array_merge
、compact
和sprintf
)。语言构造unset()
和isset()
也支持拖尾逗号。如下的样例使用 unset 函数阐述了拖尾逗号:
运行脚本,将会产生如下的输出:
array_merge()
函数是另外一个可以借助拖尾逗号简化追加值的样例。如下的脚本使用在对array_merge()
的函数调用中使用了拖尾逗号:
方法调用和闭包也允许使用拖尾逗号。在类中,方法就是一个函数。闭包是表示匿名函数的一个对象。拖尾逗号只能用于函数调用,不能用于函数声明。自由位置的逗号、前导逗号和多个拖尾逗号在该语言中是禁止使用的。
数学函数 bcscale
bcscale
函数的语法是int bcscale ([ int $scale ])
,它能够为所有后续的 bc 数学函数调用设置默认的小数位数。像bcadd()
、bcdiv()
和bcsqrt()
这样的 bc 数学函数能够用于任意精度的数字计算。PHP 7.3 添加了使用 bcscale 获取当前小数位数的支持。设置 bcscale 之后会返回旧的小数位数。作为样例,如下的脚本将默认的小数位数设置为 3,随后输出了当前的小数位数:
上述脚本的输出是 3。
新函数 is_countable
PHP 7.3 添加了新函数is_countable
,如果函数参数为array
类型或Countable
实例的话,它会返回 true。
bool is_countable(mixed $var)
例如,is_countable()
能够用来判断给定的参数是不是数组。
echo is_countable(['A', 'B', 3]);
ArrayIterator
是可数的,is_countable
会输出 TRUE,因为ArrayIterator
实现了 Countable 接口。
echo is_countable(new ArrayIterator());
is_countable<small>
可以与if()
一起使用,确保某个参数时可数的,然后再运行后续的代码。在如下的代码片段中,我们测试了类 A 的实例是不是可数的:
上述代码片段的结果是FALSE
,因为类 A 并没有实现Countable
。如果is_countable
的参数是一个数组的话,那么它将会返回TRUE
,如下面的代码片段所示:
本节所有的代码片段均放到了 is_countable.php 脚本中。
运行该脚本,输出如下所示:
箭头函数
PHP 7.4 引入了_箭头函数_,从而使匿名函数的语法更加简洁。箭头函数的形式如下所示:
fn(parameter_list) => expr
箭头函数具有最低的执行优先级,这意味着箭头 =>右边的表达式会在箭头函数之前执行,例如,箭头函数fn($x) => $x + $y
等价于fn($x) => ($x + $y)
,而不是(fn($x) => $x) + $y
。在外围作用域中声明的且被表达式中使用的变量是隐式按值捕获的。作为样例,考虑如下的脚本,它声明了一个箭头函数:
$fn1 = fn($msg) => $msg.' '.$name;
变量$name
会自动从封闭范围捕获,上述的箭头函数等价于:
对 $x 的按值绑定等价于对箭头函数中每次出现$x
均执行use($x)
。箭头函数还声明了一个参数$msg
。在下一个样例中,var_export
调用箭头函数并提供一个参数,输出值为'Hello John':
箭头函数可以进行嵌套,如下面的脚本所示。外层的脚本函数按值捕获变量$name
,内层的箭头函数从外层函数捕获$name
:
当脚本运行的时候,输出入图 2 所示。
图 2 箭头函数可以进行嵌套
因为箭头函数使用按值的变量绑定,修改箭头函数中变量的值不会影响外层作用域中的值。为了阐述这一点,如下脚本中的箭头函数递减了外层代码块中变量x 的值并没有影响,它依然是1
:
箭头函数支持任意的函数签名,可以包含参数和返回类型、默认值、可变参数以及按引用的变量传递和返回。如下的脚本阐述了箭头函数不同形式签名的使用。脚本中签名描述和输出通过注释//
进行展示。
箭头函数的对象上下文中可能会使用$this
。如果与带有 static 前缀的箭头函数一起使用,那么就不能使用$this
。为了阐述这一点,考虑如下的脚本,它在对象上下文和类上下文中使用了$this
。如果不在对象上下文中使用的话,将会输出错误信息。
总结
在该系列关于 PHP 7 新特性的第四篇(也是倒数第二篇)文章中,我们讨论了关于 PHP 函数的新特性。
在本系列的下一篇,也就是最后一篇中,我们将会讨论关于数组、操作符、常量和异常处理方面的新特性。
作者简介:
Deepak Vohra 是一位 Sun 认证的 Java 程序员和 Sun 认证的 Web 组件开发人员。Deepak 在 WebLogic Developer's Journal、XML Journal、ONJava、java.net、IBM developerWorks、Java Developer’s Journal、Oracle Magazine 和 devx 上都发表过 Java 和 Java EE 相关的技术文章。Deepak 还出版过五本关于 Docker 的书,他是 Docker 导师。Deepak 还发表了多篇关于 PHP 的文章,以及一本面向 PHP 和 Java 开发人员的 Ruby on Rails 图书。
原文链接:
Article: PHP 7 – Functions Improvements
相关阅读:
评论