说明:Laravel中常用PHP的Function Handling
来设计代码,本文主要学习PHP的Function Handling
特性,来提升写代码时的设计质量。PHP提供了一些函数处理操做的内置函数,主要有:php
call_user_func_array( )
api
call_user_func( )
数组
func_get_arg( )
app
func_get_args( )
ide
func_num_args( )
函数
function_exists( )
学习
开发环境:Laravel5.3 + PHP7
测试
call_user_func_array()是调用回调函数,并把一个数组做为参数传进去做为回调函数的参数;call_user_func()也是调用回调函数,区别是并无要求把数组做为参数传进回调函数作参数。在Laravel中大量使用这两个内置函数来设计代码,好比\Illuminate\Foundation\Application::fireAppCallbacks()的源码:this
/** * Call the booting callbacks for the application. * * @param array $callbacks * @return void */ protected function fireAppCallbacks(array $callbacks) { foreach ($callbacks as $callback) { call_user_func($callback, $this); //执行回调函数,并把Application对象做为参数传进去 } }
call_user_func()和call_user_func_array()能够说是PHP设计好代码的神器,不得不熟悉,这里给下它的PHPUnit测试看看如何使用,爆绿灯:spa
<?php namespace MyRightCapital\Container\Tests; class FunctionHandling extends \PHPUnit_Framework_TestCase { public function testCallUserFunc() { // Arrange $provider = new Provider(); $app = new Application($provider); // Actual $actual = call_user_func('MyRightCapital\Container\Tests\callUserFunc', $app); // Assert $this->assertSame('This is a service provider.', $actual); } public function testCallUserFuncArray() { // Arrange $provider = new Provider(); $app = new Application($provider); // Actual $actual = call_user_func_array('MyRightCapital\Container\Tests\callUserFunc', [$app]); // Assert $this->assertSame('This is a service provider.', $actual); } } function callUserFunc($app) { return $app->register(); } class Application { private $provider; public function __construct($provider) { $this->provider = $provider; } public function register() { return $this->provider->register(); } } class Provider { public function register() { return 'This is a service provider.'; } }
call_user_func_array()和call_user_func()真是个很是用的函数,值得在设计本身的代码里使用。
func_get_arg()是从函数的参数列表读取某个指定的参数,func_get_args()是读取函数的整个参数列表做为数组返回,func_num_args()是读取函数的参数的个数。Laravel中的IlluminateFoundationApplication::environment()
使用了这三个函数来设计代码,很巧妙:
/** * Get or check the current application environment. * * @return string|bool */ public function environment() { // 若是传入了参数 if (func_num_args() > 0) { // 若是第一个参数是数组形式就把该数组赋值给$patterns;若是不是就把全部参数做为一个数组赋值给$patterns $patterns = is_array(func_get_arg(0)) ? func_get_arg(0) : func_get_args(); foreach ($patterns as $pattern) { if (Str::is($pattern, $this['env'])) { return true; } } return false; } return $this['env']; }
看environment()源码可知道environment()是能够传入参数的,若是不传入参数就返回$this['env']
的值即Laravel中的环境变量APP_ENV值
,如App::environment()
即为读取Laravel当前运行环境变量值;若是传入参数则判断该值是否与环境变量值相等,如App::environment('production','staging', 'development')
即判断当前Laravel运行环境是不是'production','staging', 'development'
中的一种。很巧妙的设计。
这里写个PHPUnit测试下,爆绿灯:
class FunctionHandling extends \PHPUnit_Framework_TestCase { public function testFuncArgs() { // Arrange $provider = new Provider(); $app = new Application($provider); // Actual $arg_number0 = $app->testFuncArg(); $arg_number1 = $app->testFuncArg('Laravel'); $arg_number2 = $app->testFuncArg(['Laravel', 'PHP']); // Assert $this->assertSame(0, $arg_number0); $this->assertSame(1, $arg_number1); $this->assertSame(2, $arg_number2); } } class Application { private $provider; public function __construct($provider) { $this->provider = $provider; } public function register() { return $this->provider->register(); } public function testFuncArg() { if (func_num_args() > 0) { $patterns = is_array(func_get_arg(0)) ? func_get_arg(0) :func_get_args(); return count($patterns); } return 0; } }
function_exists()判断指定函数是否已经定义,这个函数在Laravel中大量使用,尤为是造辅助函数时使用,参考Illuminate/Foundation/helpers.php,Illuminate/Support/helpers.php。这里作个PHPUnit测试,爆绿灯:
class FunctionHandling extends \PHPUnit_Framework_TestCase { public function testFunctionExists() { // Arrange $expected = 'Container'; // Actual $actual = functionExists('Container'); // Assert $this->assertSame($expected, $actual); } } if (!function_exists('functionExists')) { function functionExists($container) { return $container; } }
总结:本文主要学习了PHP的Function Handling,这个技术能够用来提升本身的代码设计能力,同时Laravel中也大量使用了这个技术来巧妙设计代码。下次遇到好的技术在分享,到时见。