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());
这个匿名函数中莫名奇妙的有个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();

新增两个魔术方法__callStatic()和__invoke()

__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();

支持动态调用静态方法

class Test{    
    public static function testgo()    
    {    
         echo "gogo!";    
    }    
}    
$class = 'Test';    
$action = 'testgo';    
$class::$action();  //输出 "gogo!"

在类外也可使用const来定义常量

//并且新增了一种常量定义方式  
const CONSTANT = 'Hello World';

新增Nowdoc语法

支持通过Heredoc来初始化静态变量、类成员和类常量。

<?php    
// 静态变量    
function foo()    
{    
    static $bar = <<<LABEL    
Nothing in here...    
LABEL;    
}    
// 类成员、常量    
class foo    
{    
    const BAR = <<<FOOBAR    
Constant example    
FOOBAR;    
    
    public $baz = <<<FOOBAR    
Property example    
FOOBAR;    
}

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];

让json更懂中文

<?php
$arr = array(
  'name' => '哈哈'
);
echo json_encode($arr, JSON_UNESCAPED_UNICODE);

新增array_column()函数

<?php
$arr = array(
  array('name' => 'test1', 'age' => 22),
  array('name' => 'test2', 'age' => 23),
  array('name' => 'test3', 'age' => 24),
);
//取出name列
print_r(array_column($arr, 'name'));
//取出name列,并用age作键
print_r(array_column($arr, 'name', 'age'));

PHP5.5

yield

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";
?>

finally关键字

这个和java中的finally一样,经典的try ... catch ... finally 三段式异常处理

empty() 支持自定义函数了

<?php
function foo(){
    return false;
}
 
if(empty(foo())){
    echo 11;
} else {
    echo 12;
}

非变量array和string也能支持下标获取了

<?php
echo [1, 2, 3][0];
  
echo "foobar"[2];

PHP5.6

可以使用表达式定义常量

<?php
const ONE = 1 * 1;
class A {
  const TWO = 1 * 2;
  const THREE = self::TWO + 1;
  
  public function test($i = self::THREE + ONE) {
    echo $i;
  }
}
(new A())->test();

使用...定义变长函数参数

<?php
function total(...$nums) {
  $total = 0;
  foreach($nums as $num) {
    $total += $num;
  }
  return $total;
}
echo total(1, 2, 3, 4, 5);
$arr = [3, 4, 5, 6];
echo total(...$arr);

使用**进行幂运算

<?php
echo 2 ** 4;
$a = 2;
$a **= 4;
echo $a;

use function和use const 

<?php
namespace A {
  const PI = 3.14;
  function test() {
    echo 'test';
  }
}
namespace B {
  use function \A\test;
  use const \A\PI;
  
  echo PI;
  test();
}

PHP7

三元运算符

(expr1) ? :(expr3) 这个是php5.3开始才有的功能在 expr1 求值为 TRUE 时返回 expr1,否则返回 expr3。

(expr1) ?? (expr3) 这是PHP7开始才有的功能会判断变量(isset(expr1))是否存在来赋值,TRUE 时返回 expr1,否则返回 expr3。

函数返回值类型声明

<?php
declare(strict_types=1);

function add(int $num1, int $num2) : int {
  return $num1 + $num2;
}
echo add(2, 3);
//在严格模式下,下面这行会报错
echo add(2.0, 3.0);

通过define()定义常量数组

<?php
define('ARR', ['a', 'b', 'c']);
echo ARR[2];

匿名类

<?php
(new class {
  public function test() {
    echo 'test';
  }
})->test();

新增操作符“<=>”

语法:$c = $a <=> $b

如果$a > $b, $c 的值为1

如果$a == $b, $c 的值为0

如果$a < $b, $c 的值为-1

use 组合声明

use PHPGoodTaste\Utils\{
    Util,
    Form,
    Form\Validation,
    Form\Binding
};

PHP7.1

list支持键名

$data = [
    ["id" => 1, "name" => 'Tom'],
    ["id" => 2, "name" => 'Fred'],
];

// list() style
list("id" => $id1, "name" => $name1) = $data[0];
var_dump($id1);//1

一次捕捉多种类型的异常 / 错误

try {
      throw new LengthException("LengthException");
    //   throw new DivisionByZeroError("DivisionByZeroError");
    //   throw new Exception("Exception");
} catch (\DivisionByZeroError | \LengthException $e) {
    echo "出错消息 --- ", $e->getMessage(), PHP_EOL;
} catch (\Exception $e) {
    echo "出错消息 --- ", $e->getMessage(), PHP_EOL;
} finally {
    // ...
}

可见性修饰符的变化

class YourClass 
{
    const THE_OLD_STYLE_CONST = "One";

    public const THE_PUBLIC_CONST = "Two";
    private const THE_PRIVATE_CONST = "Three";
    protected const THE_PROTECTED_CONST = "Four";
}

可空类型

$fn = function (?int $in) : ?int {
    return $in ?? "NULL";
};

$fn(null);
$fn(5);

多种返回类型

class Number {
    private int|float $number;
 
    public function setNumber(int|float $number): void {
        $this->number = $number;
    }
 
    public function getNumber(): int|float {
        return $this->number;
    }
}

Void 返回类型

function first(): void {
    // ...
}

PHP7.2

增加新的类型object

function test(object $obj) : object
{
    return new SplQueue();
}

test(new StdClass());

允许重写抽象方法

<?php

abstract class A
{
    abstract function test(string $s);
}
abstract class B extends A
{
    // overridden - still maintaining contravariance for parameters and covariance for return
    abstract function test($s) : int;
}

\

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值