属性

类成员变量称为 *属性*。它们可以使用其他术语来引用,例如 *字段*,但为了本参考的目的,将使用 *属性*。它们是通过使用至少一个修饰符(例如 可见性static 关键字,或者从 PHP 8.1.0 开始,只读)来定义的,可选地(除了 readonly 属性),从 PHP 7.4 开始,后面跟着一个类型声明,然后是一个普通的变量声明。此声明可以包含一个初始化,但此初始化必须是一个 常量 值。

注意:

声明类属性的过时方式是使用 var 关键字而不是修饰符。

注意: 没有 可见性 修饰符声明的属性将被声明为 public

在类方法中,非静态属性可以使用 ->(对象运算符)访问:$this->property(其中 property 是属性的名称)。静态属性使用 ::(双冒号)访问:self::$property。有关静态属性和非静态属性之间区别的更多信息,请参见 static 关键字

伪变量 $this 在从对象上下文中调用该方法时在任何类方法中都可用。 $this 是调用对象的 value。

示例 #1 属性声明

<?php
class SimpleClass
{
public
$var1 = 'hello ' . 'world';
public
$var2 = <<<EOD
hello world
EOD;
public
$var3 = 1+2;
// 无效的属性声明:
public $var4 = self::myStaticMethod();
public
$var5 = $myVar;

// 有效的属性声明:
public $var6 = myConstant;
public
$var7 = [true, false];

public
$var8 = <<<'EOD'
hello world
EOD;

// 没有可见性修饰符:
static $var9;
readonly
int $var10;
}
?>

注意:

有各种函数来处理类和对象。请参见 类/对象函数 参考。

类型声明

从 PHP 7.4.0 开始,属性定义可以包括 类型声明,除了 callable

示例 #2 类型化属性示例

<?php

class User
{
public
int $id;
public ?
string $name;

public function
__construct(int $id, ?string $name)
{
$this->id = $id;
$this->name = $name;
}
}

$user = new User(1234, null);

var_dump($user->id);
var_dump($user->name);

?>

上面的示例将输出

int(1234)
NULL

类型化属性必须在访问之前初始化,否则会抛出 Error

示例 #3 访问属性

<?php

class Shape
{
public
int $numberOfSides;
public
string $name;

public function
setNumberOfSides(int $numberOfSides): void
{
$this->numberOfSides = $numberOfSides;
}

public function
setName(string $name): void
{
$this->name = $name;
}

public function
getNumberOfSides(): int
{
return
$this->numberOfSides;
}

public function
getName(): string
{
return
$this->name;
}
}

$triangle = new Shape();
$triangle->setName("triangle");
$triangle->setNumberofSides(3);
var_dump($triangle->getName());
var_dump($triangle->getNumberOfSides());

$circle = new Shape();
$circle->setName("circle");
var_dump($circle->getName());
var_dump($circle->getNumberOfSides());
?>

上面的示例将输出

string(8) "triangle"
int(3)
string(6) "circle"

Fatal error: Uncaught Error: Typed property Shape::$numberOfSides must not be accessed before initialization

只读属性

从 PHP 8.1.0 开始,可以使用 readonly 修饰符声明一个属性,这将阻止在初始化后修改该属性。

示例 #4 只读属性示例

<?php

class Test {
public readonly
string $prop;

public function
__construct(string $prop) {
// 合法初始化。
$this->prop = $prop;
}
}

$test = new Test("foobar");
// 合法读取。
var_dump($test->prop); // string(6) "foobar"

// 非法重新赋值。即使分配的值相同也不起作用。
$test->prop = "foobar";
// 错误: Cannot modify readonly property Test::$prop
?>

注意:

readonly 修饰符只能应用于 类型化属性。可以使用 混合 类型创建没有类型约束的 readonly 属性。

注意:

不支持 readonly 静态属性。

readonly 属性只能初始化一次,并且只能从声明该属性的作用域内初始化。对属性的任何其他赋值或修改都将导致 Error 异常。

示例 #5 readonly 属性的非法初始化

<?php
class Test1 {
public readonly
string $prop;
}

$test1 = new Test1;
// 非法初始化,不在私有作用域内。
$test1->prop = "foobar";
// 错误: Cannot initialize readonly property Test1::$prop from global scope
?>

注意:

不允许在 readonly 属性上指定显式默认值,因为具有默认值的 readonly 属性本质上与常量相同,因此没有特别的用处。

<?php

class Test {
// 致命错误: Readonly property Test::$prop cannot have default value
public readonly int $prop = 42;
}
?>

注意:

一旦 readonly 属性被初始化,就无法使用 unset() 删除它们。但是,可以在声明属性的作用域内,在初始化之前删除 readonly 属性。

修改不一定是简单的赋值,以下所有操作也会导致 Error 异常

<?php

class Test {
public function
__construct(
public readonly
int $i = 0,
public readonly array
$ary = [],
) {}
}

$test = new Test;
$test->i += 1;
$test->i++;
++
$test->i;
$test->ary[] = 1;
$test->ary[0][] = 1;
$ref =& $test->i;
$test->i =& $ref;
byRef($test->i);
foreach (
$test as &$prop);
?>

但是,readonly 属性并不排除内部可变性。存储在 readonly 属性中的对象(或资源)仍然可以在内部修改。

<?php

class Test {
public function
__construct(public readonly object $obj) {}
}

$test = new Test(new stdClass);
// 合法内部修改。
$test->obj->foo = 1;
// 非法重新赋值。
$test->obj = new stdClass;
?>

动态属性

如果尝试在 对象 上对一个不存在的属性进行赋值,PHP 会自动创建一个对应的属性。这个动态创建的属性只会在这个类实例上可用。

警告

从 PHP 8.2.0 开始,动态属性已弃用。建议声明属性而不是使用动态属性。要处理任意属性名称,类应该实现魔术方法 __get()__set()。在最后不得已的情况下,可以使用 #[\AllowDynamicProperties] 属性标记类。

添加注释

用户贡献的注释 6 notes

匿名
12 年前
如果这可以为任何人节省时间,我花了很多时间弄清楚为什么以下代码不起作用

class MyClass
{
private $foo = FALSE;

public function __construct()
{
$this->$foo = TRUE;

echo($this->$foo);
}
}

$bar = new MyClass();

给出 "Fatal error: Cannot access empty property in ...test_class.php on line 8"

删除访问 $foo 时的 $ 符号,进行微调,可以修复此问题

class MyClass
{
private $foo = FALSE;

public function __construct()
{
$this->foo = TRUE;

echo($this->foo);
}
}

$bar = new MyClass();

我想是因为在第一个示例中,它将 $foo 视为一个变量,因此尝试调用 $this->FALSE(或类似的代码),这是没有意义的。一旦你意识到这一点,就很明显了,但是此页面上没有显示访问的示例,说明了这一点。
anca at techliminal dot com
9 年前
您可以通过以下方式访问包含破折号的属性名(例如,因为您将 XML 文件转换为对象)

<?php
$ref
= new StdClass();
$ref->{'ref-type'} = 'Journal Article';
var_dump($ref);
?>
匿名
13 年前
$this 可以强制转换为数组。但是,这样做时,它会根据属性分类在属性名/新的数组键前添加某些数据。公有属性名不会更改。受保护的属性以空格填充的“*”作为前缀。私有属性以空格填充的类名作为前缀。

<?php

class test
{
public
$var1 = 1;
protected
$var2 = 2;
private
$var3 = 3;
static
$var4 = 4;

public function
toArray()
{
return (array)
$this;
}
}

$t = new test;
print_r($t->toArray());

/* 输出:

Array
(
[var1] => 1
[ * var2] => 2
[ test var3] => 3
)

*/
?>

这是将任何对象转换为数组时的记录行为(参见 </language.types.array.php#language.types.array.casting> PHP 手册页)。所有属性,无论可见性如何,在将对象强制转换为数组时都会显示(除了一些内置对象)。

要获得一个所有属性名都不变的数组,请在类作用域内的任何方法中使用“get_object_vars($this)”函数来检索所有属性的数组,无论外部可见性如何,或者在类作用域外使用“get_object_vars($object)”来检索仅公有属性的数组(参见:</function.get-object-vars.php> PHP 手册页)。
bernard dot dautrevaux at ac6 dot fr
5 个月前
上面没有指定,但是,至少在 PHP-8 中,使用(已弃用但仍被广泛使用)关键字“var”声明的属性被声明为“受保护的”,而不是像在引入可见性关键字之前那样声明为“公有的”。
zzzzBov
14 年前
不要将 php 版本的属性与其他语言(例如 C++)中的属性混淆。在 php 中,属性与属性相同,只是没有功能的简单变量。它们应该被称为属性,而不是属性。

属性具有隐式访问器和修改器功能。我创建了一个抽象类,它允许隐式属性功能。

<?php

abstract class PropertyObject
{
public function
__get($name)
{
if (
method_exists($this, ($method = 'get_'.$name)))
{
return
$this->$method();
}
else return;
}

public function
__isset($name)
{
if (
method_exists($this, ($method = 'isset_'.$name)))
{
return
$this->$method();
}
else return;
}

public function
__set($name, $value)
{
if (
method_exists($this, ($method = 'set_'.$name)))
{
$this->$method($value);
}
}

public function
__unset($name)
{
if (
method_exists($this, ($method = 'unset_'.$name)))
{
$this->$method();
}
}
}

?>

扩展此类后,您可以创建访问器和修改器,当访问相应的属性时,这些访问器和修改器将使用 PHP 的魔术方法自动调用。
kchlin dot lxy at gmail dot com
1 年前
从 PHP 8.1 开始
使用只读属性和提升构造函数创建 DTO 对象非常容易
这很容易打包成一个紧凑的字符串,并转换回对象。
<?php
# 转换函数。
# 将对象打包成一个紧凑的 JSON 字符串。
function cvtObjectToJson( object $poObject ): string
{
return
json_encode( array_values( get_object_vars( $poObject )));
}

# 从 JSON 字符串解包对象。
function cvtJsonToObject( string $psClass, string $psString ): object
{
return new
$psClass( ...json_decode( $psString ));
}

# DTO 示例类。
final class exampleDto
{
final public function
__construct(
public readonly
int $piInt,
public readonly ?
int $pnNull,
public readonly
float $pfFloat,
public readonly
string $psString,
public readonly array
$paArray,
public readonly
object $poObject,
){}
}

# 使用仅导出给定对象的公共属性的示例。
$exampleDtoO = new exampleDto( 1, null, .3, 'string 4', [], new stdClass() );
$stringJson = cvtObjectToJson( $exampleDtoO );// [1,null,0.3,"string 4",[],{}]
$objectO = cvtJsonToObject( exampleDto::class, $stringJson );

# 检查并 var_dump 变量。
echo $exampleDtoO == $objectO
? '对象相等,但不相同。'. PHP_EOL
: '对象不相等也不相同。'. PHP_EOL
;
var_dump($exampleDtoO, $stringJson, $objectO);

# 输出
/*
对象相等,但不相同
object(exampleDto)#6 (6) {
["piInt"]=>
int(1)
["pnNull"]=>
NULL
["pfFloat"]=>
float(0.3)
["psString"]=>
string(8) "string 4"
["paArray"]=>
array(0) {
}
["poObject"]=>
object(stdClass)#7 (0) {
}
}
string(29) "[1,null,0.3,"string 4",[],{}]"
object(exampleDto)#8 (6) {
["piInt"]=>
int(1)
["pnNull"]=>
NULL
["pfFloat"]=>
float(0.3)
["psString"]=>
string(8) "string 4"
["paArray"]=>
array(0) {
}
["poObject"]=>
object(stdClass)#9 (0) {
}
}
*/
To Top