PHP类

2023-10-23 133

一、概念

在PHP中,每个类的定义都以关键字 class 开头,后面跟着类名,而后跟着一对花括号。花括号中包含了类的属性和方法的定义;类名可以是任何非 PHP 保留字的合法标识符。一个合法的类名以字母或下划线开头,后面可以跟随任意数量的字母、数字或下划线,它可以使用正则表达式表示为:^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$。

一个类可以包含属于自己的常量、变量(称为属性)和函数(称为方法)。

二、类定义

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?<a href="https://www.zzbaike.com/tag/php" title="查看所有文章关于 php" target="_blank">php</a>
class SimpleClass
{
// 声明属性
public $var = 'a default value';
// 声明方法
public function displayVar() {
echo $this->var;
}
}
?>
<?<a href="https://www.zzbaike.com/tag/php" title="查看所有文章关于 php" target="_blank">php</a> class SimpleClass { // 声明属性 public $var = 'a default value'; // 声明方法 public function displayVar() { echo $this->var; } } ?>
<?php
class SimpleClass
{
// 声明属性
public $var = 'a default value';

// 声明方法
public function displayVar() {
echo $this->var;
}
}
?>

当一个方法在类定义内部被调用时,有一个可用的伪变量 $this,$this 是一个到当前对象的引用。

以静态方式去调用一个非静态方法,将会抛出一个 Error。 在 PHP 8.0.0 之前版本中,将会产生一个废弃通知,同时 $this 将会被声明为未定义。

例如,使用 $this 伪变量的示例:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class A
{
function foo()
{
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")\n";
} else {
echo "\$this is not defined.\n";
}
}
}
class B
{
function bar()
{
A::foo();
}
}
$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
<?php class A { function foo() { if (isset($this)) { echo '$this is defined ('; echo get_class($this); echo ")\n"; } else { echo "\$this is not defined.\n"; } } } class B { function bar() { A::foo(); } } $a = new A(); $a->foo(); A::foo(); $b = new B(); $b->bar(); B::bar(); ?>
<?php
class A
{
function foo()
{
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")\n";
} else {
echo "\$this is not defined.\n";
}
}
}

class B
{
function bar()
{
A::foo();
}
}

$a = new A();
$a->foo();

A::foo();

$b = new B();
$b->bar();

B::bar();
?>

以上示例在 PHP 7 中的输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$this is defined (A)
Deprecated: Non-static method A::foo() should not be called statically in %s on line 27
$this is not defined.
Deprecated: Non-static method A::foo() should not be called statically in %s on line 20
$this is not defined.
Deprecated: Non-static method B::bar() should not be called statically in %s on line 32
Deprecated: Non-static method A::foo() should not be called statically in %s on line 20
$this is not defined.
$this is defined (A) Deprecated: Non-static method A::foo() should not be called statically in %s on line 27 $this is not defined. Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this is not defined. Deprecated: Non-static method B::bar() should not be called statically in %s on line 32 Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this is not defined.
$this is defined (A)

Deprecated: Non-static method A::foo() should not be called statically in %s on line 27
$this is not defined.

Deprecated: Non-static method A::foo() should not be called statically in %s on line 20
$this is not defined.

Deprecated: Non-static method B::bar() should not be called statically in %s on line 32

Deprecated: Non-static method A::foo() should not be called statically in %s on line 20
$this is not defined.

在 PHP 8 中的输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$this is defined (A)
Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27
Stack trace:
#0 {main}
thrown in %s on line 27
$this is defined (A) Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27 Stack trace: #0 {main} thrown in %s on line 27
$this is defined (A)

Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27
Stack trace:
#0 {main}
   thrown in %s on line 27

三、只读类

自PHP 8.2.0版本开始,我们可以使用readonly修饰符来标记类,将类标记为readonly只会向每个属性声明添加readonly修饰符,并禁止创建动态属性。此外,不能通过使用AllowDynamicProperties注解来添加对后者的支持,尝试这样做会触发编译错误。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
#[\AllowDynamicProperties]
readonly class Foo {
}
// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
?>
<?php #[\AllowDynamicProperties] readonly class Foo { } // Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo ?>
<?php
#[\AllowDynamicProperties]
readonly class Foo {
}

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
?>

由于无类型的属性和静态属性不能用 readonly 修饰符,所以 readonly 也不会对其声明:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
readonly class Foo
{
public $bar;
}
// Fatal error: Readonly property Foo::$bar must have type
?>
<?php readonly class Foo { public $bar; } // Fatal error: Readonly property Foo::$bar must have type ?>
<?php
readonly class Foo
{
public $bar;
}

// Fatal error: Readonly property Foo::$bar must have type
?>
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
readonly class Foo
{
public static int $bar;
}
// Fatal error: Readonly class Foo cannot declare static properties
?>
<?php readonly class Foo { public static int $bar; } // Fatal error: Readonly class Foo cannot declare static properties ?>
<?php
readonly class Foo
{
public static int $bar;
}

// Fatal error: Readonly class Foo cannot declare static properties
?>

仅当子类也是 readonly 类时,才可以继承 readonly 类。

四、new关键字

要创建一个类的实例,必须使用 new 关键字。当创建新对象时该对象总是被赋值,除非该对象定义了构造函数并且在出错时抛出了一个 异常。类应在被实例化之前定义(某些情况下则必须这样)。

注意

  • 如果在 new 之后跟着的是一个包含有类名的字符串 string,则该类的一个实例被创建。
  • 如果该类属于一个命名空间,则必须使用其完整名称。
  • 如果没有参数要传递给类的构造函数,类名后的括号则可以省略掉。

1、创建实例

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
$instance = new SimpleClass();
// 也可以这样做:
$className = 'SimpleClass';
$instance = new $className(); // new SimpleClass()
?>
<?php $instance = new SimpleClass(); // 也可以这样做: $className = 'SimpleClass'; $instance = new $className(); // new SimpleClass() ?>
<?php
$instance = new SimpleClass();

// 也可以这样做:
$className = 'SimpleClass';
$instance = new $className(); // new SimpleClass()
?>

PHP 8.0.0 起,支持任意表达式中使用 new。如果表达式生成一个 string,这将允许更复杂的实例化,表达式必须使用括号括起来。

在下列示例中,我们展示了多个生成类名的任意有效表达式的示例。展示了函数调用,string 连接和 ::class 常量。

2、使用任意表达式

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class ClassA extends \stdClass {}
class ClassB extends \stdClass {}
class ClassC extends ClassB {}
class ClassD extends ClassA {}
function getSomeClass(): string
{
return 'ClassA';
}
var_dump(new (getSomeClass()));
var_dump(new ('Class' . 'B'));
var_dump(new ('Class' . 'C'));
var_dump(new (ClassD::class));
?>
<?php class ClassA extends \stdClass {} class ClassB extends \stdClass {} class ClassC extends ClassB {} class ClassD extends ClassA {} function getSomeClass(): string { return 'ClassA'; } var_dump(new (getSomeClass())); var_dump(new ('Class' . 'B')); var_dump(new ('Class' . 'C')); var_dump(new (ClassD::class)); ?>
<?php

class ClassA extends \stdClass {}
class ClassB extends \stdClass {}
class ClassC extends ClassB {}
class ClassD extends ClassA {}

function getSomeClass(): string
{
return 'ClassA';
}

var_dump(new (getSomeClass()));
var_dump(new ('Class' . 'B'));
var_dump(new ('Class' . 'C'));
var_dump(new (ClassD::class));
?>

以上示例在 PHP 8 中的输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
object(ClassA)#1 (0) {
}
object(ClassB)#1 (0) {
}
object(ClassC)#1 (0) {
}
object(ClassD)#1 (0) {
}
object(ClassA)#1 (0) { } object(ClassB)#1 (0) { } object(ClassC)#1 (0) { } object(ClassD)#1 (0) { }
object(ClassA)#1 (0) {
}
object(ClassB)#1 (0) {
}
object(ClassC)#1 (0) {
}
object(ClassD)#1 (0) {
}

在类定义内部,可以用 new self 和 new parent 创建新对象。

当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。可以用克隆给一个已创建的对象建立一个新实例。

3、对象赋值

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
$instance = new SimpleClass();
$assigned = $instance;
$reference =& $instance;
$instance->var = '$assigned will have this value';
$instance = null; // $instance 和 $reference 变为 null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>
<?php $instance = new SimpleClass(); $assigned = $instance; $reference =& $instance; $instance->var = '$assigned will have this value'; $instance = null; // $instance 和 $reference 变为 null var_dump($instance); var_dump($reference); var_dump($assigned); ?>
<?php

$instance = new SimpleClass();

$assigned = $instance;
$reference =& $instance;

$instance->var = '$assigned will have this value';

$instance = null; // $instance 和 $reference 变为 null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

以上示例会输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned will have this value"
}
NULL NULL object(SimpleClass)#1 (1) { ["var"]=> string(30) "$assigned will have this value" }
NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned will have this value"
}

有几种方法可以创建一个对象的实例。

4、创建新对象

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class Test
{
static public function getNew()
{
return new static;
}
}
class Child extends Test
{}
$obj1 = new Test();
$obj2 = new $obj1;
var_dump($obj1 !== $obj2);
$obj3 = Test::getNew();
var_dump($obj3 instanceof Test);
$obj4 = Child::getNew();
var_dump($obj4 instanceof Child);
?>
<?php class Test { static public function getNew() { return new static; } } class Child extends Test {} $obj1 = new Test(); $obj2 = new $obj1; var_dump($obj1 !== $obj2); $obj3 = Test::getNew(); var_dump($obj3 instanceof Test); $obj4 = Child::getNew(); var_dump($obj4 instanceof Child); ?>
<?php
class Test
{
static public function getNew()
{
return new static;
}
}

class Child extends Test
{}

$obj1 = new Test();
$obj2 = new $obj1;
var_dump($obj1 !== $obj2);

$obj3 = Test::getNew();
var_dump($obj3 instanceof Test);

$obj4 = Child::getNew();
var_dump($obj4 instanceof Child);
?>

以上示例会输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
bool(true)
bool(true)
bool(true)
bool(true) bool(true) bool(true)
bool(true)
bool(true)
bool(true)

5、通过一个表达式来访问新创建对象的成员

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
echo (new DateTime())->format('Y');
?>
<?php echo (new DateTime())->format('Y'); ?>
<?php
echo (new DateTime())->format('Y');
?>

以上示例的输出类似于:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
2016
2016
2016

注意: 在 PHP 7.1 之前,如果类没有定义构造函数,则不对参数进行执行。

五、属性和方法

类的属性和方法存在于不同的“命名空间”中,这意味着同一个类的属性和方法可以使用同样的名字。 在类中访问属性和调用方法使用同样的操作符,具体是访问一个属性还是调用一个方法,取决于你的上下文,即用法是变量访问还是函数调用。

1、访问类属性 vs. 调用类方法

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class Foo
{
public $bar = 'property';
public function bar() {
return 'method';
}
}
$obj = new Foo();
echo $obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;
<?php class Foo { public $bar = 'property'; public function bar() { return 'method'; } } $obj = new Foo(); echo $obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;
<?php
class Foo
{
public $bar = 'property';

public function bar() {
return 'method';
}
}

$obj = new Foo();
echo $obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;

以上示例会输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
property
method
property method
property
method

这意味着,如果类属性被分配给一个匿名函数你将无法直接调用它。因为访问类属性的优先级要更高,在此场景下需要用括号包裹起来调用。

2、类属性被赋值为匿名函数时的调用示例

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class Foo
{
public $bar;
public function __construct() {
$this->bar = function() {
return 42;
};
}
}
$obj = new Foo();
echo ($obj->bar)(), PHP_EOL;
<?php class Foo { public $bar; public function __construct() { $this->bar = function() { return 42; }; } } $obj = new Foo(); echo ($obj->bar)(), PHP_EOL;
<?php
class Foo
{
public $bar;

public function __construct() {
$this->bar = function() {
return 42;
};
}
}

$obj = new Foo();

echo ($obj->bar)(), PHP_EOL;

以上示例会输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
42
42
42

六、extends关键字

一个类可以在声明中用 extends 关键字继承另一个类的方法和属性。PHP 不支持多重继承,一个类只能继承一个基类。被继承的方法和属性可以通过用同样的名字重新声明被覆盖,但是如果父类定义方法或者常量时使用了 final,则不可被覆盖,可以通过 parent:: 来访问被覆盖的方法或属性。

注意: 从 PHP 8.1.0 起,常量可以声明为 final。

1、简单的类继承

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class ExtendClass extends SimpleClass
{
// 同样名称的方法,将会覆盖父类的方法
function displayVar()
{
echo "Extending class\n";
parent::displayVar();
}
}
$extended = new ExtendClass();
$extended->displayVar();
?>
<?php class ExtendClass extends SimpleClass { // 同样名称的方法,将会覆盖父类的方法 function displayVar() { echo "Extending class\n"; parent::displayVar(); } } $extended = new ExtendClass(); $extended->displayVar(); ?>
<?php
class ExtendClass extends SimpleClass
{
// 同样名称的方法,将会覆盖父类的方法
function displayVar()
{
echo "Extending class\n";
parent::displayVar();
}
}

$extended = new ExtendClass();
$extended->displayVar();
?>

以上示例会输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Extending class
a default value
Extending class a default value
Extending class
a default value

七、签名兼容性规则

当覆盖(override)方法时,签名必须兼容父类方法,否则会导致 Fatal 错误,PHP 8.0.0 之前是 E_WARNING 级错误。 兼容签名是指:遵守协变与逆变规则;强制参数可以改为可选参数;添加的新参数只能是可选;放宽可见性而不是继续限制。这就是著名的里氏替换原则(Liskov Substitution Principle),简称 LSP。不过构造方法和私有(private)方法不需要遵循签名兼容规则,哪怕签名不匹配也不会导致 Fatal 错误。

1、兼容子类方法

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class Base
{
public function foo(int $a) {
echo "Valid\n";
}
}
class Extend1 extends Base
{
function foo(int $a = 5)
{
parent::foo($a);
}
}
class Extend2 extends Base
{
function foo(int $a, $b = 5)
{
parent::foo($a);
}
}
$extended1 = new Extend1();
$extended1->foo();
$extended2 = new Extend2();
$extended2->foo(1);
<?php class Base { public function foo(int $a) { echo "Valid\n"; } } class Extend1 extends Base { function foo(int $a = 5) { parent::foo($a); } } class Extend2 extends Base { function foo(int $a, $b = 5) { parent::foo($a); } } $extended1 = new Extend1(); $extended1->foo(); $extended2 = new Extend2(); $extended2->foo(1);
<?php
class Base
{
public function foo(int $a) {
echo "Valid\n";
}
}

class Extend1 extends Base
{
function foo(int $a = 5)
{
parent::foo($a);
}
}

class Extend2 extends Base
{
function foo(int $a, $b = 5)
{
parent::foo($a);
}
}

$extended1 = new Extend1();
$extended1->foo();
$extended2 = new Extend2();
$extended2->foo(1);

以上示例会输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Valid
Valid
Valid Valid
Valid
Valid

下面演示子类与父类方法不兼容的例子:通过移除参数、修改可选参数为必填参数。

2、子类方法移除参数后,导致 Fatal 错误

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class Base
{
public function foo(int $a = 5) {
echo "Valid\n";
}
}
class Extend extends Base
{
function foo()
{
parent::foo(1);
}
}
<?php class Base { public function foo(int $a = 5) { echo "Valid\n"; } } class Extend extends Base { function foo() { parent::foo(1); } }
<?php

class Base
{
public function foo(int $a = 5) {
echo "Valid\n";
}
}

class Extend extends Base
{
function foo()
{
parent::foo(1);
}
}

以上示例在 PHP 8 中的输出类似于:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13
Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13
Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13

3、子类方法把可选参数改成强制参数,导致 Fatal 错误

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class Base
{
public function foo(int $a = 5) {
echo "Valid\n";
}
}
class Extend extends Base
{
function foo(int $a)
{
parent::foo($a);
}
}
<?php class Base { public function foo(int $a = 5) { echo "Valid\n"; } } class Extend extends Base { function foo(int $a) { parent::foo($a); } }
<?php

class Base
{
public function foo(int $a = 5) {
echo "Valid\n";
}
}

class Extend extends Base
{
function foo(int $a)
{
parent::foo($a);
}
}

以上示例在 PHP 8 中的输出类似于:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13
Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13
Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13

重命名子类方法的参数名称也是签名兼容的,不建议这样做,因为使用命名参数时, 这种做法会导致运行时的 Error。

4、在子类中重命一个命名参数,导致 Error

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class A {
public function test($foo, $bar) {}
}
class B extends A {
public function test($a, $b) {}
}
$obj = new B;
// 按 A::test() 的签名约定传入参数
$obj->test(foo: "foo", bar: "bar"); // ERROR!
<?php class A { public function test($foo, $bar) {} } class B extends A { public function test($a, $b) {} } $obj = new B; // 按 A::test() 的签名约定传入参数 $obj->test(foo: "foo", bar: "bar"); // ERROR!
<?php

class A {
public function test($foo, $bar) {}
}

class B extends A {
public function test($a, $b) {}
}

$obj = new B;

// 按 A::test() 的签名约定传入参数
$obj->test(foo: "foo", bar: "bar"); // ERROR!

以上示例的输出类似于:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14
Stack trace:
#0 {main}
thrown in /in/XaaeN on line 14
Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14 Stack trace: #0 {main} thrown in /in/XaaeN on line 14
Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14
Stack trace:
#0 {main}
thrown in /in/XaaeN on line 14

八、::class

关键词 class 也可用于类名的解析。使用 ClassName::class 可以获取包含类 ClassName 的完全限定名称,这对使用了命名空间的类尤其有用。

1、类名的解析

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
namespace NS {
class ClassName {
}
echo ClassName::class;
}
?>
<?php namespace NS { class ClassName { } echo ClassName::class; } ?>
<?php
namespace NS {
class ClassName {
}

echo ClassName::class;
}
?>

以上示例会输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
NS\ClassName
NS\ClassName
NS\ClassName

注意:使用 ::class 解析类名操作会在底层编译时进行。这意味着在执行该操作时,类还没有被加载。 因此,即使要调用的类不存在,类名也会被展示。在此种场景下,并不会发生错误。

2、解析不存在的类名

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
print Does\Not\Exist::class;
?>
<?php print Does\Not\Exist::class; ?>
<?php
print Does\Not\Exist::class;
?>

以上示例会输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Does\Not\Exist
Does\Not\Exist
Does\Not\Exist

自 PHP 8.0.0 起,::class 也可用于对象。 与上述情况不同,此时解析将会在运行时进行。此操作的运行结果和在对象上调用 get_class() 相同。

2、类名解析

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
namespace NS {
class ClassName {
}
}
$c = new ClassName();
print $c::class;
?>
<?php namespace NS { class ClassName { } } $c = new ClassName(); print $c::class; ?>
<?php
namespace NS {
class ClassName {
}
}
$c = new ClassName();
print $c::class;
?>

以上示例会输出:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
NS\ClassName
NS\ClassName
NS\ClassName

九、Nullsafe方法和属性

自 PHP 8.0.0 起,类属性和方法可以通过 “nullsafe” 操作符访问: ?->, 除了一处不同,nullsafe 操作符和以上原来的属性、方法访问是一致的: 对象引用解析(dereference)为 null 时不抛出异常,而是返回 null。 并且如果是链式调用中的一部分,剩余链条会直接跳过。

此操作的结果,类似于在每次访问前使用 is_null() 函数判断方法和属性是否存在,但更加简洁。

1、Nullsafe操作符

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
// 自 PHP 8.0.0 起可用
$result = $repository?->getUser(5)?->name;
// 上边那行代码等价于以下代码
if (is_null($repository)) {
$result = null;
} else {
$user = $repository->getUser(5);
if (is_null($user)) {
$result = null;
} else {
$result = $user->name;
}
}
?>
<?php // 自 PHP 8.0.0 起可用 $result = $repository?->getUser(5)?->name; // 上边那行代码等价于以下代码 if (is_null($repository)) { $result = null; } else { $user = $repository->getUser(5); if (is_null($user)) { $result = null; } else { $result = $user->name; } } ?>
<?php

// 自 PHP 8.0.0 起可用
$result = $repository?->getUser(5)?->name;

// 上边那行代码等价于以下代码
if (is_null($repository)) {
$result = null;
} else {
$user = $repository->getUser(5);
if (is_null($user)) {
$result = null;
} else {
$result = $user->name;
}
}
?>

注意:仅当 null 被认为是属性或方法返回的有效和预期的可能值时,才推荐使用 nullsafe 操作符。如果业务中需要明确指示错误,抛出异常会是更好的处理方式。

  • 广告合作

  • QQ群号:4114653

温馨提示:
1、本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。邮箱:2942802716#qq.com(#改为@)。 2、本站原创内容未经允许不得转裁,转载请注明出处“站长百科”和原文地址。
PHP类
上一篇: PHP箭头函数
PHP类
下一篇: PHP类属性