【php5.3的新增、改进】匿名函数
也叫闭包(closures), 经常被用来临时性地创建一个无名函数,用于回调函数等用途。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
$func = function ($arg) {
print $arg;
};
$func("hello world");
匿名函数还可以用 use 关键字来捕捉外部变量:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
function arrayplus($array, $num)
{
array_walk($array, function (&$v) use ($num) {
$v += $num;
});
}
上面的代码定义了一个 arrayplus() 函数(这不是匿名函数), 它会将一个数组($array)中的每一项,加上一个指定的数字($num).在 arrayplus() 的实现中,我们使用了 array_walk() 函数,它会为一个数组的每一项执行一个回调函数,即我们定义的匿名函数。在匿名函数的参数列表后,我们用 use 关键字将匿名函数外的 $num 捕捉到了函数内,以便知道到底应该加上多少。
后期静态绑定php的继承模型中有一个存在已久的问题,那就是在父类中引用扩展类的最终状态比较困难。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
<?php
class parentbase
static $property = 'parent value';
public static function render()
{
return self::$property;
}
class descendant extends parentbase
static $property = 'descendant value';
//output: parent value
echo descendant::render();
在这个例子中,render()方法中使用了self关键字,这是指parentbase类而不是指descendant类。在 parentbase::render()方法中没法访问$property的最终值。为了解决这个问题,需要在子类中重写render()方法。通过引入延迟静态绑定功能,可以使用static作用域关键字访问类的属性或者方法的最终值
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
return static::$property;
public static function status()
static::getstatus();
protected static function getstatus()
echo "person is alive";
//output: descendant value
php的面向对象体系中,提供了若干“魔术方法”,用于实现类似其他语言中的“重载”,如在访问不存在的属性、方法时触发某个魔术方法。
__call($funcname, $arguments)
__callstatic($funcname, $arguments)
参数说明:
$funcname string 调用的不存在的方法名称。
$arguments array 调用方法时所带的参数。
__invoke魔术方法会在将一个对象作为函数调用时被调用:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
class a
public function __invoke($args)
print "a::__invoke(): {$args}";
$a = new a;
//output: a::__invoke(): hello world
$a("hello world");
__callstatic则会在调用一个不存在的静态方法时被调用,有了__callstatic,可以省不少代码了。而且这个方法支持在子类中调用,配合上get_called_class,子类也一起魔术了
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
class activerecordbase
/** as of php 5.3.0 */
public static function __callstatic($func, $arguments)
if ($func == 'getbyid') {
$id = $arguments[0];
return get_called_class() . '(' . $id . ')';
}
throw new exception('invalid method : ' . $name);
class person extends activerecordbase
// output: person(123)
echo person::getbyid(123);
__call 当要调用的方法不存在或权限不足时,会自动调用__call 方法。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
class db
private $sql = array(
"field" => "",
"where" => "",
"order" => "",
"limit" => "",
"group" => "",
"having" => "",
);
// 连贯操作调用field() where() order() limit() group() having()方法,组合sql语句
function __call($methodname, $args)
// 将第一个参数(代表不存在方法的方法名称),全部转成小写方式,获取方法名称
$methodname = strtolower($methodname);
// 如果调用的方法名和成员属性数组$sql下标对应上,则将第二个参数给数组中下标对应的元素
if (array_key_exists($methodname, $this->sql)) {
$this->sql[$methodname] = $args[0];
} else {
echo '调用类' . get_class($this) . '中的方法' . $methodname . '()不存在';
// 返回自己对象,则可以继续调用本对象中的方法,形成连贯操作
return $this;
// 输出连贯操作后组合的一个sql语句,是连贯操作最后的一个方法
function select()
echo "select {$this->sql['field']} from user {$this->sql['where']} {$this->sql['order']} {$this->sql['limit']} {$this->sql['group']}
{$this->sql['having']}";
$db = new db();
// 连贯操作
$db->field('sex, count(sex)')
->where('where sex in ("男","女")')
->group('group by sex')
->having('having avg(age) > 25')
->select();
?>
命名空间一个最明确的目的就是解决重名问题,php中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误。这种情况下只要避免命名重复就可以解决,最常见的一种做法是约定一个前缀。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
//创建空间blog
namespace blog;
class comment
//非限定名称,表示当前blog空间
//这个调用将被解析成 blog\comment();
$blog_comment = new comment();
//限定名称,表示相对于blog空间
//这个调用将被解析成 blog\article\comment();
$article_comment = new article\comment(); //类前面没有反斜杆\
//完全限定名称,表示绝对于blog空间
$article_comment = new \blog\comment(); //类前面有反斜杆\
$article_comment = new \blog\article\comment(); //类前面有反斜杆\
//创建blog的子空间article
namespace blog\article;
别名和导入可以看作是调用命名空间元素的一种快捷方式。php并不支持导入函数或常量。 它们都是通过使用use操作符来实现:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
//创建一个bbs空间(我有打算开个论坛)
namespace bbs;
//导入一个命名空间
use blog\article;
//导入命名空间后可使用限定名称调用元素
$article_comment = new article\comment();
//为命名空间使用别名
use blog\article as arte;
//使用别名代替空间名
$article_comment = new arte\comment();
//导入一个类
use blog\article\comment;
//导入类后可使用非限定名称调用元素
$article_comment = new comment();
//为类使用别名
use blog\article\comment as comt;
$article_comment = new comt();
php5.4
数组简写形式
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
//原来的数组写法
$arr = array("key" => "value", "key2" => "value2");
// 简写形式
$arr = ["key" => "value", "key2" => "value2"];
traits
所谓traits就是“构件”,是用来替代继承的一种机制。trait和类相似,但不能被实例化php中无法进行多重继承,但一个类可以包含多个traits.
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
trait sayworld
public $var = 'test';
public function sayhello()
echo 'world!';
class myhelloworld
// 将sayworld中的成员包含进来
use sayworld;
$xxoo = new myhelloworld();
// sayhello()函数是来自sayworld构件的 $xxoo->var
$xxoo->sayhello();
traits还有很多神奇的功能,比如包含多个traits, 解决冲突,修改访问权限,为函数设置别名等等。
新增在实例化时访问类成员的特征:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
(new myclass)->xxoo();
新增支持对函数返回数组的成员访问解析
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
print [1, 2, 3][0];
php5.5
yield的一个功能就是能有效的降低迭代的内存开销,yield关键字用于当函数需要返回一个迭代器的时候, 逐个返回值.也就是说, 每当产生一个数组元素, 就通过yield关键字返回成一个, 并且函数执行暂停, 当返回的迭代器的next方法被调用的时候, 会恢复刚才函数的执行, 从上一次被yield暂停的位置开始继续执行, 到下一次遇到yield的时候, 再次返回.
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
function generators()
for ($i = 1; $i <= 10; $i += 1) {
yield $i;
foreach (generators() as $v) {
echo $v;
可以用 list() 在 foreach 中解析嵌套的数组:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5ichR3cf52bjl2LcNXZnFWbp9CXt92YuUWelRXauYjM5cmbvlXZkVHavw1LcpDc0RHaiojIsJye.png)
$array = [
[1, 2, 3],
[4, 5, 6],
];
foreach ($array as list($a, $b, $c))
echo "{$a} {$b} {$c}\n";
aaa