PHP>5.3版本部分新功能

【PHP5.3的新增、改进】匿名函数
也叫闭包(Closures), 经常被用来临时性地创建一个无名函数,用于回调函数等用途。

$func = function ($arg) {
    print $arg;
};
$func("Hello World");
<?php
$f = function () {
    return 100;
};

function testClosure(Closure $callback) {
    return $callback();
}

$a = testClosure($f);
print_r($a); //100
exit;
如果要调用一个类里面的匿名函数呢
<?php

class C
{
    public static function testC() {
        return function ($i) {
            return $i + 100;
        };
    }
}


function testClosure(Closure $callback) {
    return $callback(13);
}

$a = testClosure(C::testC());
print_r($a);exit;
其中的C::testC()返回的是一个funciton,我们就需要将“一个匿名函数绑定到一个类中”。
<?php
class A{
    public $base = 100;
}
$f = function () {
    return $this->base + 3;
};

$a = Closure::bind($f, new A);
print_r($a());
f这个匿名函数中莫名奇妙的有个this,这个this关键词就是说明这个匿名函数是需要绑定在类中的。绑定之后,就好像A中有这么个函数一样,但是这个函数是public还是private,bind的最后一个参数就说明了这个函数的可调用范围 匿名函数还可以用 use 关键字来捕捉外部变量:
function arrayPlus($array, $num)
{
    array_walk($array, function (&$v) use ($num) {
        $v += $num;
    });
}
上面的代码定义了一个 arrayPlus() 函数(这不是匿名函数), 它会将一个数组($array)中的每一项,加上一个指定的数字($num).在 arrayPlus() 的实现中, 我们使用了 array_walk() 函数,它会为一个数组的每一项执行一个回调函数,即我们定义的匿名函数。在匿名函数的参数列表后,我们用 use 关键字将匿名函数外的 $num 捕捉到了函数内,以便知道到底应该加上多少。 PHP参数类型约束,不论是接口,抽象类,函数,方法,在5.3+以上版本都可以使用,不过目前只能声明 array,object ,可执行类型( callable.Closure)这3种.ConnectionInterface就是属于object
public function addConnection($name, ConnectionInterface $connection)
{
    $this->connections[$name] = $connection;
}
  后期静态绑定PHP的继承模型中有一个存在已久的问题,那就是在父类中引用扩展类的最终状态比较困难。
<?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作用域关键字访问类的属性或者方法的最终值
<?php

class ParentBase
{
    static $property = 'Parent Value';

    public static function render()
    {
        return static::$property;
    }
}

class Descendant extends ParentBase
{
    static $property = 'Descendant Value';
}

//output: Descendant Value
echo Descendant::render();
PHP的面向对象体系中,提供了若干“魔术方法”,用于实现类似其他语言中的“重载”,如在访问不存在的属性、方法时触发某个魔术方法。

__call($funcname, $arguments)

__callStatic($funcname, $arguments)

参数说明:

$funcname String 调用的不存在的方法名称。

$arguments Array 调用方法时所带的参数。
 __invoke魔术方法会在将一个对象作为函数调用时被调用:

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,子类也一起魔术了
<?php

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 方法。

<?php

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中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误。这种情况下只要避免命名重复就可以解决,最常见的一种做法是约定一个前缀。

<?php
//创建空间Blog
namespace Blog;

class Comment
{
}

//非限定名称,表示当前Blog空间
//这个调用将被解析成 Blog\Comment();
$blog_comment = new Comment();

//限定名称,表示相对于Blog空间
//这个调用将被解析成 Blog\Article\Comment();
$article_comment = new Article\Comment(); //类前面没有反斜杆\

//完全限定名称,表示绝对于Blog空间
//这个调用将被解析成 Blog\Comment();
$article_comment = new \Blog\Comment(); //类前面有反斜杆\

//完全限定名称,表示绝对于Blog空间
//这个调用将被解析成 Blog\Article\Comment();
$article_comment = new \Blog\Article\Comment(); //类前面有反斜杆\


//创建Blog的子空间Article
namespace Blog\Article;

class Comment
{
}
?>
别名和导入可以看作是调用命名空间元素的一种快捷方式。PHP并不支持导入函数或常量。 它们都是通过使用use操作符来实现:
<?php
namespace Blog\Article;

class Comment
{
}

//创建一个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();
?>
php内置的类,不隶属于任何命名空间如果你需要在命名空间中使用须有 \ 声明
new \DateTime();
PHP5.4

数组简写形式

<?php
//原来的数组写法
$arr = array("key" => "value", "key2" => "value2");
// 简写形式
$arr = ["key" => "value", "key2" => "value2"];
?>
Traits
所谓Traits就是“构件”,是用来替代继承的一种机制。Trait和类相似,但不能被实例化 PHP中无法进行多重继承,但一个类可以包含多个Traits.
<?php
trait SayWorld
{
    public $var = 'test';
    public function sayHello()
    {
        echo 'World!';
    }
}

class MyHelloWorld
{
    // 将SayWorld中的成员包含进来
    use SayWorld;
}

$xx = new MyHelloWorld();
// sayHello()函数是来自SayWorld构件的 $xx->var
$xx->sayHello();
Traits还有很多神奇的功能,比如包含多个Traits, 解决冲突,修改访问权限,为函数设置别名等等。
<?php

class A
{
    public function callFuncTest() {
        print $this->funcTest();
    }

    public function funcTest() {
        return "this is A::funcTest().<br/>";
    }
}
$func = "funcTest";
echo A::{$func}();
echo (new A)->funcTest();
新增在实例化时访问类成员的特征
(new MyClass)->xx();
 新增支持对函数返回数组的成员访问解析
print [1, 2, 3][0];
  PHP5.5 yield的一个功能就是能有效的降低迭代的内存开销,yield关键字用于当函数需要返回一个迭代器的时候, 逐个返回值.也就是说, 每当产生一个数组元素, 就通过yield关键字返回成一个, 并且函数执行暂停, 当返回的迭代器的next方法被调用的时候, 会恢复刚才函数的执行, 使用上yield实现,里面所有的中间变量都只使用一个内存$i,这样节省的时间和空间都会变小.从上一次被yield暂停的位置开始继续执行, 到下一次遇到yield的时候, 再次返回.
<?php
function generators()
{
    for ($i = 1; $i <= 10; $i += 1) {
        yield $i;
    }

}

foreach (generators() as $v) {
    echo $v;
}
 可以用 list() 在 foreach 中解析嵌套的数组:
$array = [
    [1, 2, 3],
    [4, 5, 6],
];

foreach ($array as list($a, $b, $c))
    echo "{$a} {$b} {$c}\n";
 类名通过::class可以获取
<?php
namespace Name\Space;
class ClassName {}
 
echo ClassName::class;
 
echo "\n";
?>
 PHP7函数 返回值类型声明(注意 … 的边长参数语法在 PHP 5.6 以上的版本中才有)
<?php

namespace DesignPatterns\Creational\AbstractFactory;

class JsonFactory extends AbstractFactory
{
    public function createText(string $content): Text
    {
        return new JsonText($content);
    }
}
 return的结果必须是Text对象
<?php
function arraysSum(array ...$arrays): array 
{ 
    return array_map(function(array $array): int { 
        return array_sum($array); 
    }, $arrays); 
} 

print_r(arraysSum([1,2,3], [4,5,6], [7,8,9])); 

猜你喜欢

转载自hudeyong926.iteye.com/blog/2279010
今日推荐