PHP Migrating to 7.4 8.0

2023-08-23 18:51:05 浏览数 (1)

  • 实验环境:https://onlinephp.io/

  • Polyfill https://github.com/symfony/polyfill/tree/main/src

PHP7.3 to PHP7.4

https://www.php.net/manual/en/migration74.php https://php.watch/versions/7.4 PHP 7.4, the final release in the PHP 7.x series. PHP 7.4 brings typed properties, underscore numeric separator, and other minor improvements to PHP.

New Features 7.4

代码语言:javascript复制
// Typed properties
class User {
    public int $id; // 会强制要求 $user->id 只能为 int 类型,访问前必须进行处理化,?int 也要进行初始化
}
代码语言:javascript复制
// 箭头函数 Arrow functions
$factor = 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);
代码语言:javascript复制
// 有限的 Limited 返回类型协变和参数类型逆变
class A {}
class B extends A {}
class Producer {
    public function method(): A {}
}
class ChildProducer extends Producer {
    public function method(): B {}
}
// PHP74
// ok
//
// PHP73
// Fatal error: Declaration of ChildProducer::method(): B must be compatible with Producer::method(): A
代码语言:javascript复制
// 空合并赋值运算符
$array['key1'] ??= 1;
// is roughly equivalent to
if (!isset($array['key2'])) {
    $array['key2'] = 2;
}
var_dump($array);
// array(2) {
//   ["key1"]=>
//   int(1)
//   ["key2"]=>
//   int(2)
// }
代码语言:javascript复制
// Unpacking inside arrays
// 可以平替 array_merge
$parts = ['apple', 'pear'];
$fruits = ['orange', ...$parts, 'watermelon'];
var_dump($fruits);
// array(4) {
//   [0]=>
//   string(6) "orange"
//   [1]=>
//   string(5) "apple"
//   [2]=>
//   string(4) "pear"
//   [3]=>
//   string(10) "watermelon"
// }
代码语言:javascript复制
// 数字文字分隔符
6.674_083e-11; // float
299_792_458;   // decimal
0xCAFE_F00D;   // hexadecimal
0b0101_1111;   // binary

var_dump((int)"1_123");
// int(1)
代码语言:javascript复制
// WeakReference 类
// https://www.php.net/manual/zh/class.weakreference.php
$obj = new stdClass;
$weakref = WeakReference::create($obj);
var_dump($weakref->get());
unset($obj);
var_dump($weakref->get());
// object(stdClass)#1 (0) {
// }
// NULL

Backward Incompatible Changes 7.4

代码语言:javascript复制
// 以数组形式访问非数组,将会抛出 notic
// null, bool, int, float or resource
$i = 12;
$i["a"];
// PHP74
// Notice: Trying to access array offset on value of type int
//
// PHP80
// Warning: Trying to access array offset on value of type int
//
// PHP73 ok

Deprecated Features 7.4

代码语言:javascript复制
// 嵌套的三元运算必须明确地使用括号来指示运算的顺序
var_dump(1 ? 2 : 3 ? 4 : 5);
// PHP74
// Deprecated: Unparenthesized `a ? b : c ? d : e` is deprecated. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)`
// int(4)

PHP7.4 to PHP8.0

https://www.php.net/manual/en/migration80.php

New Features 8.0

代码语言:javascript复制
// 命名参数
// https://www.php.net/manual/zh/functions.arguments.php#functions.named-arguments
// array_fill(int $start_index, int $count, mixed $value): array
var_dump(array_fill(value: 50, count: 3, start_index: 0));
// PHP80
// array(3) {
//   [0]=>
//   int(50)
//   [1]=>
//   int(50)
//   [2]=>
//   int(50)
// }
代码语言:javascript复制
// 注解(Attributes)
// https://www.php.net/manual/zh/language.attributes.php
// 定义注解 -> 使用注解 -> (通过反射)提取注释
// 注意以后用词:Attributes 注解,Properties 属性
#[Attribute]
class JsonSerialize {
    public function __construct(public ?string $fieldName = null) {
        var_dump("JsonSerialize:$fieldName");
    }
}
class VersionedObject {
    #[JsonSerialize('json-foobar')]
    protected string $myValue = '';
}
$object = new VersionedObject();
$reflection = new ReflectionObject($object);
foreach ($reflection->getProperties() as $reflectionProp) {
    foreach ($reflectionProp->getAttributes(JsonSerialize::class) as $jsonSerializeAttr) {
        var_dump($jsonSerializeAttr->getName());
        var_dump($jsonSerializeAttr->getArguments());
        var_dump($jsonSerializeAttr->getTarget());
        var_dump($jsonSerializeAttr->isRepeated());
        var_dump($jsonSerializeAttr->newInstance());
    }
}
// string(13) "JsonSerialize"
//
// array(1) {
//   [0]=>
//   string(11) "json-foobar"
// }
//
// int(8) Attribute::TARGET_PROPERTY
//
// bool(false)
//
// string(25) "JsonSerialize:json-foobar"
// object(JsonSerialize)#5 (1) {
//   ["fieldName"]=>
//   string(11) "json-foobar"
// }
代码语言:javascript复制
// 构造器属性提升
// 当构造器参数带访问控制(visibility modifier)时,PHP 会同时把它当作对象属性和构造器参数,并赋值到属性
class Point {
    public function __construct(protected int $x, protected int $y = 0) {
    }
}
var_dump(new Point(2,4));
// object(Point)#1 (2) {
//   ["x":protected]=>
//   int(2)
//   ["y":protected]=>
//   int(4)
// }
class Point {
    public function __construct(int $x, int $y = 0) {
        $this->x = $x;
        $this->y = $y;
    }
}
var_dump(new Point(2,4));
// object(Point)#1 (2) {
//   ["x"]=>
//   int(2)
//   ["y"]=>
//   int(4)
// }

class Point2 {
    protected int $x;
    protected int $y;
    public function __construct(protected int $x, protected int $y = 0) {}
}
// 此类中已经定义了具有相同名称的字段
// Fatal error: Cannot redeclare Point::$x
代码语言:javascript复制
// Union types 联合类型
// ?T is same T|null
//
// - 类型只能出现一次 int|string|INT 否则报错
// - 使用 mixed 会报错
// - bool 与 false or true 不能混用
// - object 与 class 不能混用
// - iterable 与 array Traversable 不能混用
// - 使用 self、parent 或 static 都会导致错误
代码语言:javascript复制
// match 表达式
// https://www.php.net/manual/en/control-structures.match.php
// match 表达式必须是详尽,则会抛出 UnhandledMatchError。
$food = 'cake';
$return_value = match ($food) {
    'apple' => 'This food is an apple',
    'bar' => 'This food is a bar',
    'cake' => 'This food is a cake',
};
var_dump($return_value);
// string(19) "This food is a cake"
代码语言:javascript复制
// Nullsafe 方法和属性
// As of PHP 8.0.0, this line:
$result = $repository?->getUser(5)?->name;
// Is equivalent to the following code block:
if (is_null($repository)) {
    $result = null;
} else {
    $user = $repository->getUser(5);
    if (is_null($user)) {
        $result = null;
    } else {
        $result = $user->name;
    }
}
代码语言:javascript复制
// The WeakMap class has been added, accepts objects as keys, similar SplObjectStorage
// https://www.php.net/manual/en/class.weakmap.php
// https://www.php.net/manual/en/class.splobjectstorage.php
// final class WeakMap implements ArrayAccess, Countable, IteratorAggregate
$wm = new WeakMap();
$o = new StdClass;
class A {
    public function __destruct() {
        echo "Dead!n";
    }
}
$wm[$o] = new A;
var_dump(count($wm));
// int(1)
unset($o);
// Dead!
// 销毁
var_dump(count($wm));
// int(0)


// 对比 SplObjectStorage
$wm = new SplObjectStorage();
$o = new StdClass;
class A {
    public function __destruct() {
        echo "Dead!n";
    }
}
$wm[$o] = new A;
var_dump(count($wm));
// int(1)
unset($o);
// 未销毁
var_dump(count($wm));
// int(1)
代码语言:javascript复制
// 只要类型兼容,现在可以将任意数量的函数参数替换为可变参数 variadic argument
class A {
    public function method(int $many, string $parameters, $here) {}
}
class B extends A {
    public function method(...$everything) {}
}
// OK
class C extends A {
    public function method(int ...$everything) {}
}
// Fatal error: Declaration of C::method(int ...$everything)
代码语言:javascript复制
// static 后期静态绑定,现在可以用作返回类型
class Test {
    public function create(): static {
        return new static();
    }
}
代码语言:javascript复制
// get_class($obj) === $obj::class
class Test {}
$obj = new Test;
var_dump($obj::class);
var_dump(get_class($obj));
代码语言:javascript复制
// new instanceof 可以与任意表达式一起使用
// new (expression)(...$args)
// $obj instanceof (expression)
class A{};
class B{};
new (1>2 ? "A" : "B")();
代码语言:javascript复制
// 新增 Stringable 接口。如果 class 定义了 __toString(),则自动实现了此接口
代码语言:javascript复制
// Traits can define abstract private methods
trait T {
    abstract private function a();
}
代码语言:javascript复制
// throw 可以作为一个表达式 as an expression
$fn = fn() => throw new Exception('Exception in arrow function');
代码语言:javascript复制
// 参数列表中现在允许使用可选的尾随逗号
function functionWithLongSignature(
    Type1 $parameter1,
    Type2 $parameter2, // <-- This comma is now allowed.
) {}
代码语言:javascript复制
// 允许 catch (Exception) 无需存储到变量
try {}
catch (Exception) {}
代码语言:javascript复制
// 在父类上声明的私有方法不再对子类的方法强制执行任何继承规则(私有构造函数除外)
class ParentClass {
    private function method1() {}
    private function method2() {}
    private static function method3() {}
}
abstract class ChildClass extends ParentClass {
    public abstract function method1();
    public static function method2() {}
    public function method3() {}
}
// OK

Backward Incompatible Changes 8.0

代码语言:javascript复制
// 字符串与数字比较
// 0 == "not-a-number" is false
// 将数字转换为字符串,并使用字符串比较
var_dump(0 == "foo");
var_dump(42 == "42foo");
var_dump(0 == "");
// PHP80
// bool(false)
// bool(false)
// bool(false)
//
// PHP74
// bool(true)
// bool(true)
// bool(true)
var_dump("" < 0);
var_dump("" < -1);
var_dump("a" < 0);
var_dump("b" < -1);
var_dump("ab" > 0);
// PHP80
// bool(true)
// bool(true)
// bool(false)
// bool(false)
// bool(true)
//
// PHP74
// bool(false)
// bool(false)
// bool(false)
// bool(false)
// bool(false)
代码语言:javascript复制
// match is 保留关键字
代码语言:javascript复制
// is_callable() 在检查具有 classname 的 non-static 方法时将 false(必须检查对象实例)
class Test {
    public function method1() {}
}
var_dump(is_callable([Test::class, 'method1']));
var_dump(is_callable([new Test, 'method1']));
// PHP80
// bool(false)
// bool(true)
//
// PHP74
// bool(true)
// bool(true)
代码语言:javascript复制
// __autoload() function has been removed
代码语言:javascript复制
// 删除了对 object 使用 array_key_exists() 的能力。isset() or property_exists() may be used instead

– EOF –

  • # php

0 人点赞