欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

PHP特性整合(PHP5.X到PHP7.1.x)

程序员文章站 2023-09-20 00:01:26
PHP7 已经出来1年了,PHP7.1也即将和大家见面,这么多好的特性,好的方法,为什么不使用呢,也希望PHP越来越好。 在这里整理 PHP 5.1 ,PHP5.2,PHP5.3...

PHP7 已经出来1年了,PHP7.1也即将和大家见面,这么多好的特性,好的方法,为什么不使用呢,也希望PHP越来越好。
在这里整理 PHP 5.1 ,PHP5.2,PHP5.3,PHP5.4,PHP5.5,PHP5.6 ,PHP7,PHP7.1 所有新特性

Buid-in web server内置了一个简单的Web服务器

把当前目录作为Root Document只需要这条命令即可:

php -S localhost:3300

也可以指定其它路径

php -S localhost:3300 -t /path/to/root  

还可以指定路由

php -S localhost:3300 router.php

命名空间(php5.3)

命名空间的分隔符为反斜杆\

namespace fox\lanmps\Table;    
class Select {}

获取完整类别名称

PHP5.3 中引入命名空间的别名类和命名空间短版本的功能。虽然这并不适用于字符串类名称

use Some\Deeply\Nested\Namespace\FooBar;    
// does not work, because this will try to use the global `FooBar` class    
$reflection = new ReflectionClass('FooBar');   
echo FooBar::class;  

为了解决这个问题采用新的FooBar::class语法,它返回类的完整类别名称

命名空间 use 操作符开始支持函数和常量的导入

namespace Name\Space {  
    const FOO = 42;  
    function f() { echo __FUNCTION__."\n"; }  
}  
namespace {  
    use const Name\Space\FOO;  
    use function Name\Space\f;  

    echo FOO."\n";  
    f();  
} 

输出
42
Name\Space\f

Group use declarations

从同一 namespace 导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了。

//PHP7之前
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;
use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;
use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;

// PHP7之后
use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};

支持延迟静态绑定

static关键字来引用当前类,即实现了延迟静态绑定

class A {    
    public static function who() {    
        echo __CLASS__;    
    }    
    public static function test() {    
        static::who(); // 这里实现了延迟的静态绑定    
    }    
}    
class B extends A {    
    public static function who() {    
         echo __CLASS__;    
    }    
}
B::test();    

输出结果:
B

支持goto语句

多数计算机程序设计语言中都支持无条件转向语句goto,当程序执行到goto语句时,即转向由goto语句中的标号指出的程序位置继续执行。尽管goto语句有可能会导致程序流程不清晰,可读性减弱,但在某些情况下具有其独特的方便之处,例如中断深度嵌套的循环和 if 语句。

goto a;    
echo 'Foo';    
a:    
echo 'Bar';    
for($i=0,$j=50; $i<100; $i++) {    
  while($j--) {    
    if($j==17) goto end;    
  }     
}    
echo "i = $i";    
end:    
echo 'j hit 17'; 

支持闭包、Lambda/Anonymous函数

闭包(Closure)函数和Lambda函数的概念来自于函数编程领域。例如JavaScript 是支持闭包和 lambda 函数的最常见语言之一。
在PHP中,我们也可以通过create_function()在代码运行时创建函数。但有一个问题:创建的函数仅在运行时才被编译,而不与其它代码同时被编译成执行码,因此我们无法使用类似APC这样的执行码缓存来提高代码执行效率。
在PHP5.3中,我们可以使用Lambda/匿名函数来定义一些临时使用(即用即弃型)的函数,以作为array_map()/array_walk()等函数的回调函数。

echo preg_replace_callback('~-([a-z])~', function ($match) {    
    return strtoupper($match[1]);    
}, 'hello-world');    
// 输出 helloWorld    
$greet = function($name)    
{    
    printf("Hello %s\r\n", $name);    
};    
$greet('World');    
$greet('PHP');    
//...在某个类中    
$callback =      function ($quantity, $product) use ($tax, &$total)         {    
   $pricePerItem = constant(__CLASS__ . "::PRICE_" .  strtoupper($product));    
   $total += ($pricePerItem * $quantity) * ($tax + 1.0);    
 };    

魔术方法__callStatic()和__invoke()

PHP中原本有一个魔术方法__call(),当代码调用对象的某个不存在的方法时该魔术方法会被自动调用。新增的__callStatic()方法则只用于静态类方法。当尝试调用类中不存在的静态方法时,__callStatic()魔术方法将被自动调用。

class MethodTest {    
    public function __call($name, $arguments) {    
        // 参数 $name 大小写敏感    
        echo "调用对象方法 '$name' "    
             . implode(' -- ', $arguments). "\n";    
    }    
    /**  PHP 5.3.0 以上版本中本类方法有效  */    
    public static function __callStatic($name, $arguments) {    
        // 参数 $name 大小写敏感    
        echo "调用静态方法 '$name' "    
             . implode(' -- ', $arguments). "\n";    
    }    
}    

$obj = new MethodTest;    
$obj->runTest('通过对象调用');    
MethodTest::runTest('静态调用');  // As of PHP 5.3.0

以上代码执行后输出如下:
调用对象方法’runTest’ –- 通过对象调用调用静态方法’runTest’ –- 静态调用
以函数形式来调用对象时,__invoke()方法将被自动调用。

class MethodTest {    
    public function __call($name, $arguments) {    
        // 参数 $name 大小写敏感    
        echo "Calling object method '$name' "    
             . implode(', ', $arguments). "\n";    
    }    

    /**  PHP 5.3.0 以上版本中本类方法有效  */    
    public static function __callStatic($name, $arguments) {    
        // 参数 $name 大小写敏感    
        echo "Calling static method '$name' "    
             . implode(', ', $arguments). "\n";    
    }    
}    
$obj = new MethodTest;    
$obj->runTest('in object context');    
MethodTest::runTest('in static context');  // As of PHP 5.3.0  

Nowdoc语法

用法和Heredoc类似,但使用单引号。Heredoc则需要通过使用双引号来声明。
Nowdoc中不会做任何变量解析,非常适合于传递一段PHP代码。

// Nowdoc 单引号 PHP 5.3之后支持    
$name = 'MyName';    
echo <<<'EOT'    
My name is "$name".    
EOT;    
//上面代码输出 My name is "$name". ((其中变量不被解析)    
// Heredoc不加引号    
echo <<

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

// 静态变量    
function foo()    
{    
    static $bar = <<



//PHP中定义常量通常是用这种方式  
define("CONSTANT", "Hello world.");  

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

$expr1=1;
$expr2=2;
//原格式  
$expr=$expr1?$expr1:$expr2  
//新格式  
$expr=$expr1?:$expr2

$param = $_GET['param'] ?? 1;

$param = isset($_GET['param']) ? $_GET['param'] : 1;

echo json_encode("中文", JSON_UNESCAPED_UNICODE);  
//输出:"中文" 

$bin  = 0b1101;  
echo $bin;  
//13 

 echo "\u{9876}"

printf("2 ** 3 ==      %d\n", 2 ** 3);
printf("2 ** 3 ** 2 == %d\n", 2 ** 3 ** 2);

$a = 2;
$a **= 3;
printf("a ==           %d\n", $a);

// Integers
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1
// Floats
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1
// Strings
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1

官网的一个例子:  
trait SayWorld {  
        public function sayHello() {  
                parent::sayHello();  
                echo "World!\n";  
                echo 'ID:' . $this->id . "\n";  
        }  
}  

class Base {  
        public function sayHello() {  
                echo 'Hello ';  
        }  
}  

class MyHelloWorld extends Base {  
        private $id;  

        public function __construct() {  
                $this->id = 123456;  
        }  

        use SayWorld;  
}  

$o = new MyHelloWorld();  
$o->sayHello();  

/*will output: 
Hello World! 
ID:123456 
 */  

$arr = [1,'james', 'james@fwso.cn'];  
$array = [  
  "foo" => "bar",  
  "bar" => "foo"  
  ]; 

function myfunc() {  
    return array(1,'james', 'james@fwso.cn');  
}
echo myfunc()[1];  

$name = explode(",", "Laruence,male")[0];  
explode(",", "Laruence,male")[3] = "phper";  

echo array(1, 2, 3)[0];  
echo [1, 2, 3][0];  
echo "foobar"[2];  

var_dump("abcdef"[-2]);
var_dump(strpos("aabbcc", "b", -3));

string (1) "e"
int(3)

function randomHexString($length) {    
    $str = '';    
    for ($i = 0; $i < $length; ++$i) {    
        $str .= "0123456789abcdef"[mt_rand(0, 15)]; // direct dereference of string    
    }    
}    
function randomBool() {    
    return [false, true][mt_rand(0, 1)]; // direct dereference of array    
}   

const A = 2;  
const B = A + 1;  
class C  
{  
    const STR = "hello";  
    const STR2 = self::STR + ", world";  
}

function test($arg = C::STR2)

class ConstDemo
{
    const PUBLIC_CONST_A = 1;
    public const PUBLIC_CONST_B = 2;
    protected const PROTECTED_CONST = 3;
    private const PRIVATE_CONST = 4;
}

define('ANIMALS', ['dog', 'cat', 'bird']);
echo ANIMALS[1]; // outputs "cat"

class bar {  
function foo(bar $foo) {  
}  
//其中函数foo中的参数规定了传入的参数必须为bar类的实例,否则系统会判断出错。同样对于数组来说,也可以进行判断,比如:  
function foo(array $foo) {  
}  
}  
  foo(array(1, 2, 3)); // 正确,因为传入的是数组  
  foo(123); // 不正确,传入的不是数组

function add(int $a) 
{ 
    return 1+$a; 
} 
var_dump(add(2));

function foo(int $i) { ... }  
foo(1);      // $i = 1  
foo(1.0);    // $i = 1  
foo("1");    // $i = 1  
foo("1abc"); // not yet clear, maybe $i = 1 with notice  
foo(1.5);    // not yet clear, maybe $i = 1 with notice  
foo([]);     // error  
foo("abc");  // error  

function create_query($where, $order_by, $join_type='', $execute = false, $report_errors = true) { ... }  

create_query("deleted=0", "name", default, default, false);  

function add(...$args)  
{  
    $result = 0;  
    foreach($args as $arg)  
        $result += $arg;  
    return $result;  
} 

function test(?string $name)
{
    var_dump($name);
}

string(5) "tpunt"
NULL
Uncaught Error: Too few arguments to function test(), 0 passed in...

function swap(&$left, &$right) : void
{
    if ($left === $right) {
        return;
    }
    $tmp = $left;
    $left = $right;
    $right = $tmp;
}
$a = 1;
$b = 2;
var_dump(swap($a, $b), $a, $b);

null
int(2)
int(1)

function show(): array 
{ 
    return [1,2,3,4]; 
}

function arraysSum(array ...$arrays): array
{
return array_map(function(array $array): int {
return array_sum($array);
}, $arrays);
}

function add($a, $b, $c) {  
    return $a + $b + $c;  
}  
$arr = [2, 3];  
add(1, ...$arr);

class test{  
    function show(){  
return 'test';  
    }  
}  
echo (new test())->show();

foreach ([new Human("Gonzalo"), new Human("Peter")] as $human) {  
    echo $human->{'hello'}();  
} 

function foo(callable $callback) {  
}

foo("false"); //错误,因为false不是callable类型  
  foo("printf"); //正确  
  foo(function(){}); //正确  
class A {  
  static function show() {  
    }  
}  
  foo(array("A", "show")); //正确

class TimePeriod {  
    public $seconds;  
    public $hours {  
        get { return $this->seconds / 3600; }  
        set { $this->seconds = $value * 3600; }  
    }  
}  
$timePeriod = new TimePeriod;  
$timePeriod->hours = 10;  
var_dump($timePeriod->seconds); // int(36000)  
var_dump($timePeriod->hours);   // int(10)  

function *xrange($start, $end, $step = 1) {  
    for ($i = $start; $i < $end; $i += $step) {  
        yield $i;  
    }  
}  
foreach (xrange(10, 20) as $i) {  
    // ...  
}  

$firstNames = [foreach ($users as $user) yield $user->firstName];  

$firstNames = [];  
foreach ($users as $user) {  
    $firstNames[] = $user->firstName;  
}

$underageUsers = [foreach ($users as $user) if ($user->age < 18) yield $user];  

function generator()
{
    yield 1;
    yield 2;
    yield 3;
    return "a";
}

$generatorClass = ("generator")();
foreach ($generatorClass as $val) {
    echo $val ." ";

}
echo $generatorClass->getReturn();

function generator1()
{
    yield 1;
    yield 2;
    yield from generator2();
    yield from generator3();
}

function generator2()
{
    yield 3;
    yield 4;
}

function generator3()
{
    yield 5;
    yield 6;
}

foreach (generator1() as $val) {
    echo $val, " ";
}

try {
    // some code
} catch (FirstException | SecondException $e) {
    // handle first and second exceptions
} catch (\Exception $e) {
    // ...
} finally{
//
}

$array = [  
    [1, 2],  
    [3, 4],  
];  
foreach ($array as list($a, $b)) {  
    echo "A: $a; B: $b\n";  
} 

$data = [
    ['id' => 1, 'name' => 'Tom'],
    ['id' => 2, 'name' => 'Fred'],
];
while (['id' => $id, 'name' => $name] = $data) {
    // logic here with $id and $name
}

$data = [
    ['id' => 1, 'name' => 'Tom'],
    ['id' => 2, 'name' => 'Fred'],
];
while (list('id' => $id, 'name' => $name) = $data) {
    // logic here with $id and $name
}

function iterator(iterable $iter)
{
    foreach ($iter as $val) {
        //
    }
}

class Test
{
    public function exposeFunction()
    {
        return Closure::fromCallable([$this, 'privateFunction']);
    }
    private function privateFunction($param)
    {
        var_dump($param);
    }
}
$privFunc = (new Test)->exposeFunction();
$privFunc('some value');

string(10) "some value"

interface Logger
{
    public function log(string $msg);
}

class Application
{
    private $logger;

    public function getLogger(): Logger
    {
        return $this->logger;
    }

    public function setLogger(Logger $logger)
    {
        $this->logger = $logger;
    }
}

$app = new Application;
$app->setLogger(new class implements Logger
{
    public function log(string $msg)
    {
        echo $msg;
    }
});
var_dump($app->getLogger());

class Test
{
    public $name = "lixuan";
}

//PHP7和PHP5.6都可以
$getNameFunc = function () {
    return $this->name;
};
$name = $getNameFunc->bindTo(new Test, 'Test');
echo $name();
//PHP7可以,PHP5.6报错
$getX = function () {
    return $this->name;
};
echo $getX->call(new Test);

SIGHUP

function test($param){}
test();

Uncaught Error: Too few arguments to function test(), 0 passed in %s on line %d and exactly 1 expected in %s:%d

(function () {
    'func_num_args'();
})();

Warning: Cannot call func_num_args() dynamically in %s on line %d

$array = [0, 1, 2];
foreach ($array as &$val) {
    var_dump(current($array));
}

$array = [0];
foreach ($array as &$val) {
    var_dump($val);
    $array[1] = 1;
}

var_dump("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));

class C {}
$c =& new C;

class A {
    public function test() { var_dump($this); }
}
// 注意:并没有从类 A 继承
class B {
    public function callNonStaticMethodOfA() { A::test(); }
}
(new B)->callNonStaticMethodOfA();

echo yield -1;
// 在之前版本中会被解释为:
echo (yield) - 1;
// 现在,它将被解释为:
echo yield (-1);
yield $foo or die;
// 在之前版本中会被解释为:
yield ($foo or die);
// 现在,它将被解释为:
(yield $foo) or die;