可见性

属性、方法或(从 PHP 7.1.0 开始)常量的可见性可以通过在声明前添加关键字 publicprotectedprivate 来定义。声明为 public 的类成员可以在任何地方访问。声明为 protected 的成员只能在类本身和继承类以及父类中访问。声明为 private 的成员只能被定义该成员的类访问。

属性可见性

类属性可以定义为 public、private 或 protected。没有显式可见性关键字的属性定义为 public。

示例 #1 属性声明

<?php
/**
* 定义 MyClass
*/
class MyClass
{
public
$public = 'Public';
protected
$protected = 'Protected';
private
$private = 'Private';

function
printHello()
{
echo
$this->public;
echo
$this->protected;
echo
$this->private;
}
}

$obj = new MyClass();
echo
$obj->public; // 可行
echo $obj->protected; // 致命错误
echo $obj->private; // 致命错误
$obj->printHello(); // 显示 Public、Protected 和 Private


/**
* 定义 MyClass2
*/
class MyClass2 extends MyClass
{
// 我们可以重新声明 public 和 protected 属性,但不能声明 private
public $public = 'Public2';
protected
$protected = 'Protected2';

function
printHello()
{
echo
$this->public;
echo
$this->protected;
echo
$this->private;
}
}

$obj2 = new MyClass2();
echo
$obj2->public; // 可行
echo $obj2->protected; // 致命错误
echo $obj2->private; // 未定义
$obj2->printHello(); // 显示 Public2、Protected2、未定义

?>

方法可见性

类方法可以定义为 public、private 或 protected。没有显式可见性关键字的方法定义为 public。

示例 #2 方法声明

<?php
/**
* 定义 MyClass
*/
class MyClass
{
// 声明一个 public 构造函数
public function __construct() { }

// 声明一个 public 方法
public function MyPublic() { }

// 声明一个 protected 方法
protected function MyProtected() { }

// 声明一个 private 方法
private function MyPrivate() { }

// 这是 public
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}

$myclass = new MyClass;
$myclass->MyPublic(); // 可行
$myclass->MyProtected(); // 致命错误
$myclass->MyPrivate(); // 致命错误
$myclass->Foo(); // Public、Protected 和 Private 可行


/**
* 定义 MyClass2
*/
class MyClass2 extends MyClass
{
// 这是 public
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // 致命错误
}
}

$myclass2 = new MyClass2;
$myclass2->MyPublic(); // 可行
$myclass2->Foo2(); // Public 和 Protected 可行,Private 不行

class Bar
{
public function
test() {
$this->testPrivate();
$this->testPublic();
}

public function
testPublic() {
echo
"Bar::testPublic\n";
}

private function
testPrivate() {
echo
"Bar::testPrivate\n";
}
}

class
Foo extends Bar
{
public function
testPublic() {
echo
"Foo::testPublic\n";
}

private function
testPrivate() {
echo
"Foo::testPrivate\n";
}
}

$myFoo = new Foo();
$myFoo->test(); // Bar::testPrivate
// Foo::testPublic
?>

常量可见性

从 PHP 7.1.0 开始,类常量可以定义为 public、private 或 protected。没有显式可见性关键字的常量定义为 public。

示例 #3 从 PHP 7.1.0 开始的常量声明

<?php
/**
* 定义 MyClass
*/
class MyClass
{
// 声明一个公有常量
public const MY_PUBLIC = 'public';

// 声明一个受保护的常量
protected const MY_PROTECTED = 'protected';

// 声明一个私有常量
private const MY_PRIVATE = 'private';

public function
foo()
{
echo
self::MY_PUBLIC;
echo
self::MY_PROTECTED;
echo
self::MY_PRIVATE;
}
}

$myclass = new MyClass();
MyClass::MY_PUBLIC; // 可用
MyClass::MY_PROTECTED; // 致命错误
MyClass::MY_PRIVATE; // 致命错误
$myclass->foo(); // 公有、受保护和私有都可用


/**
* 定义 MyClass2
*/
class MyClass2 extends MyClass
{
// 这是公有的
function foo2()
{
echo
self::MY_PUBLIC;
echo
self::MY_PROTECTED;
echo
self::MY_PRIVATE; // 致命错误
}
}

$myclass2 = new MyClass2;
echo
MyClass2::MY_PUBLIC; // 可用
$myclass2->foo2(); // 公有和受保护可用,私有不可用
?>

从其他对象访问

同一类型的对象可以访问彼此的私有和受保护成员,即使它们不是同一个实例。这是因为在这些对象内部,实现细节已经知道。

示例 #4 访问同一对象类型的私有成员

<?php
class Test
{
private
$foo;

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

private function
bar()
{
echo
'访问了私有方法。';
}

public function
baz(Test $other)
{
// 我们可以更改私有属性:
$other->foo = 'hello';
var_dump($other->foo);

// 我们也可以调用私有方法:
$other->bar();
}
}

$test = new Test('test');

$test->baz(new Test('other'));
?>

上面的示例将输出

string(5) "hello"
Accessed the private method.
添加一个注释

用户贡献的注释 7 个注释

pgl at yoyo dot org
9 年前
只是一个快速说明,可以同时声明多个属性的可见性,方法是用逗号隔开它们。

例如

<?php
class a
{
protected
$a, $b;

public
$c, $d;

private
$e, $f;
}
?>
r dot wilczek at web-appz dot de
18 年前
注意:可见性在每个类基础上工作,并不阻止同一类的实例访问彼此的属性!

<?php
class Foo
{
private
$bar;

public function
debugBar(Foo $object)
{
// 这不违反可见性,尽管 $bar 是私有的
echo $object->bar, "\n";
}

public function
setBar($value)
{
// 必要的 method,因为 $bar 在类外部是不可见的
$this->bar = $value;
}

public function
setForeignBar(Foo $object, $value)
{
// 这不违反可见性!
$object->bar = $value;
}
}

$a = new Foo();
$b = new Foo();
$a->setBar(1);
$b->setBar(2);
$a->debugBar($b); // 2
$b->debugBar($a); // 1
$a->setForeignBar($b, 3);
$b->setForeignBar($a, 4);
$a->debugBar($b); // 3
$b->debugBar($a); // 4
?>
alperenberatdurmus at gmail dot com
1 年前
动态属性是“公有的”。
<?php
class MyClass {
public function
setProperty($value) {
$this->dynamicProperty = $value;
}
}
$obj = new MyClass();
$obj->setProperty('Hello World');
echo
$obj->dynamicProperty; // 输出 "Hello World"
?>

此用法也是相同的
<?php
class MyClass {
}
$obj = new MyClass();
$obj->dynamicProperty = 'Hello World';
echo
$obj->dynamicProperty; // 输出 "Hello World"
?>
jc dot flash at gmail dot com
12 年前
如果未被覆盖,子类中的 self::$foo 实际上是指向父类的 self::$foo
<?php
class one
{
protected static
$foo = "bar";
public function
change_foo($value)
{
self::$foo = $value;
}
}

class
two extends one
{
public function
tell_me()
{
echo
self::$foo;
}
}
$first = new one;
$second = new two;

$second->tell_me(); // bar
$first->change_foo("restaurant");
$second->tell_me(); // restaurant
?>
Joshua Watt
17 年前
我在任何地方都找不到关于这一点的文档,但你可以像预期的那样访问同一类的不同实例中的受保护和私有成员变量



<?php
A
{
protected
$prot;
private
$priv;

public function
__construct($a, $b)
{
$this->prot = $a;
$this->priv = $b;
}

public function
print_other(A $other)
{
echo
$other->prot;
echo
$other->priv;
}
}

B extends A
{
}

$a = new A("a_protected", "a_private");
$other_a = new A("other_a_protected", "other_a_private");

$b = new B("b_protected", "ba_private");

$other_a->print_other($a); // 输出 a_protected 和 a_private
$other_a->print_other($b); // 输出 b_protected 和 ba_private

$b->print_other($a); // 输出 a_protected 和 a_private
?>
bishop at php dot net
7 年前
> 声明为 protected 的成员只能在类本身和继承类中访问。声明为 private 的成员只能由定义该成员的类访问。
>
>
>

这并不完全正确。对象外部的代码可以获取和设置私有和受保护成员

<?php
Sealed { private $value = 'foo'; }

$sealed = new Sealed;
var_dump($sealed); // private $value => string(3) "foo"

call_user_func(\Closure::bind(
function () use (
$sealed) { $sealed->value = 'BAZ'; },
null,
$sealed
));

var_dump($sealed); // private $value => string(3) "BAZ"

?>

神奇之处在于 \Closure::bind,它允许匿名函数绑定到特定类作用域。\Closure::bind 的文档中提到

> 如果提供了对象,则将使用该对象的类型
> 而不是。这将确定绑定对象中受保护和
> 私有方法的可见性。

因此,实际上,我们为 $sealed 添加了一个运行时设置器,然后调用该设置器。这可以扩展为可以强制设置和强制获取对象成员的通用函数

<?php
function force_set($object, $property, $value) {
call_user_func(\Closure::bind(
function () use (
$object, $property, $value) {
$object->{$property} = $value;
},
null,
$object
));
}

function
force_get($object, $property) {
return
call_user_func(\Closure::bind(
function () use (
$object, $property) {
return
$object->{$property};
},
null,
$object
));
}

force_set($sealed, 'value', 'quux');
var_dump(force_get($sealed, 'value')); // 'quux'

?>

您可能不应该在生产环境中依赖此功能,但对于调试和测试来说,拥有此功能非常方便。
kostya at eltexsoft dot com
2 年前
我看到我们可以将私有属性重新声明到子类中
<?php
A{
private
int $private_prop = 4;
protected
int $protected_prop = 8;
}

B extends A{
private
int $private_prop = 7; // 我们可以重新声明私有属性!!!
public function printAll() {
echo
$this->private_prop;
echo
$this->protected_prop;
}
}

$b = new B;
$b->printAll(); // 显示 78
}
?>
To Top