php发展

首页 » 常识 » 常识 » 深入PHP74类型属性实例详解虫虫搜
TUhjnbcbe - 2024/12/30 9:51:00
白癜风在北京能治好吗 https://yiyuan.99.com.cn/bjzkbdfyy/zljs/261180.html

根据PHPRFC日程,PHP7.4预期将会在今年11月份,当然接下来PHP8被也已经上了历程。7.4将至,PHP8可期!那么即将到来PHP7.4有啥新特性和功能呢?本文以虫虫以类型方面的增强来予以介绍和大家一起学习。

概述

PHP7.4为了增强类型新增加了类型化的类属性,并对PHP的类型系统进行了重大改进。当然这些变化都是可选功能,是完全向前对老版本兼容,不会破坏以前的老代码。新的类型特性:

从PHP7.4开始支持。

仅在类中可用,并且需要访问修饰符:public,protected或private或var。

允许使用除了void和callable以外的所有类型。

其表现如下例:

Uninitialized

在上面的例子中,首先映入我们眼帘的是:

classFoo{

publicint$bar;

}

$foo=newFoo;

即使创建Foo对象后$bar的值不是整数,PHP只会在访问$bar时抛出错误:

var_dump($foo-a);

Fatalerror:UncaughtError:TypedpropertyFoo::$bar

mustnotbeaccessedbeforeinitialization

从错误消息可以得出,有一种新的可变状态:uninitialized。

如果$bar没有类型,则其值将为null。类型可以是空值,无法确定是否设置了类型化的可空属性,或者忘记设置了。所以新添加了uninitialized这个新类型加以区别。

关于uninitialized,主要注意:

无法访问未初始化的属性,如果坚持要访问会抛出致命错误。

在访问属性时会检查未初始化状态,所以即使其类型不可为空,也可以创建具有未初始化属性的对象。

可以在读取之前写入未初始化的属性。

对类型化属性使用unset将使其未初始化,取消设置无类型属性将使设置为null。

下面例子中在构造对象后设置未初始化的,不可为空的属性,是有效的:

classFoo{

publicint$a;

}

$foo=newFoo;

$foo-a=1;

虽然只是读取属性值时检查未初始化状态,但在写入时会进行类型验证。所以可以确保不会被赋予错误类型的属性值。

默认值和构造函数

再来看看如何初始化类型值。在标量类型的情况下,可以提供默认值:

classFoo{

publicint$bar=4;

public?string$baz=null;

publicarray$list=[1,2,3];

}

注意,如果类型实际上可以为空,则只能使用null作为默认值。可能看起来很明显,但是参数默认值存在一些遗留行为,其中允许以下内容:

functionpassNull(int$i=null)

{/*…*/}

passNull(null);

好消息是,类型属性不允许这种令人困惑的行为。

另请注意对对象或类类型的默认值是不可设置的。应该使用构造函数来设置其默认值。

初始化类型值的显而易见的地方当然是构造函数:

classFoo{

privateint$a;

publicfunction__construct(int$a){

$this-a=$a;

}

}

在构造函数之外写入未初始化的属性是有效的。只要不去访问这些属性,就不会执行未初始化的检查。

支持的类型

上面我们说了类型属性只能在类中使用,并且需要访问修饰符或前面的var关键字。从可用类型来看,除了void和callable之外,几乎所有类型都可以使用。void类型表示没有值,它不能用于键入值。然而,callable类型则更复杂点。

PHP中的callable类型用法是:

$callable=[$this,method];

假设你代码如下:

在上面的示例中,$callable引用私有的Bar::method方法,但是调用是在Foo的上下文中调用。由于作用域不同,所以callable的支持也不能再类型属性中使用。

这没什么大不了的,因为Closure是一个有效的类型,它将记住构造它的$this上下文。

除此之外,所有可用类型的列表如下:

布尔型(bool),整型(int),浮点型(float),字符串(string),数组(array),iterable,对象,?(nullable),self和parent,类和接口

强制和严格的类型

PHP具有动态语言具有的类型灵活性,它会尽可能地强制或转换类型。假设传递给整型变量一个字符串,PHP将尝试自动转换该字符串:

functioncoerce(int$i)

{…}

coerce(1);//1

类型属性也使用同样的原则。以下代码有效,会自动将1转换为1。

classBar{

publicint$i;

}

$bar=newBar;

$bar-i=1;//1

如果不喜欢这种行为,可以通过声明为严格类型检查来禁用:

declare(strict_types=1);

$bar=newBar;$bar-i=1;

上述语句以错误类型赋值时候,在严格类型检查(strict_types=1)下会抛出验严重错误:

Fatalerror:UncaughtTypeError:

TypedpropertyBar::$imustbeint,stringused

类型变量和继承

尽管PHP7.4引入了改进的类型变量,但类型属性仍然是不变的。这意味着以下内容无效:

classA{}

classBextendsA{}

classFoo

{

publicA$prop;

}

classBarextendsFoo

{

publicB$prop;

}

Fatalerror:TypeofBar::$propmustbeA(asinclassFoo)

如果上面的看起起不明显,再举个例子:

classFoo

{

publicself$prop;

}

classBarextendsFoo

{

publicself$prop;

}

在运行代码之前,PHP将使用它引用的具体类后台替换self。所以上面的代码也会抛出相同的错误。处理它的唯一正确姿势是:

classFoo

{

publicFoo$prop;

}

classBarextendsFoo

{

publicFoo$prop;

}

说到继承,可能会发现很难找到任何好的用例来覆盖继承属性的类型。

值得注意的是,可以更改继承属性的类型,但前提是访问修饰符也从私有更改为protected或public。下面代码是正确的:

classFoo

{

privateint$prop;

}

classBarextendsFoo

{

publicstring$prop;

}

不允许将类型从可空变为非可空,反之亦然。

classFoo

{

publicint$a;

public?int$b;

}

classBarextendsFoo

{

public?int$a;

publicint$b;

}

Fatalerror:TypeofBar::$amustbeint(asinclassFoo)

总结

本文我们以类型化属性是PHP为例介绍了PHP7.4带来的新的变化和加强,更多的功能,可以参考PHPRFC。对于即将到来的7.4版本和后面可期的PHP8,我们只有以活到老,学到老的态度才能跟上新技术的步伐。求求你别更新了,我快跟不上啦!绝非一个IT人应该有的态度!

1
查看完整版本: 深入PHP74类型属性实例详解虫虫搜