什么时候以及为什么我应该在类中使用公共、私有和受保护的函数和变量?它们之间的区别是什么?

例子:

// Public
public $variable;
public function doSomething() {
  // ...
}

// Private
private $variable;
private function doSomething() {
  // ...
}

// Protected
protected $variable;
protected function doSomething() {
  // ...
}

当前回答

又提了一个老问题,但我认为从你所定义的API的角度来考虑这个问题是一个很好的方法。

public——所有标记为public的东西都是API的一部分,任何使用你的类/接口/其他的人都会使用和依赖它。 protected -不要被愚弄了,这也是API的一部分!人们可以子类化,扩展你的代码,使用任何标记为受保护的东西。 private -私有属性和方法可以随心所欲地更改。没有其他人可以使用这些。这些是唯一可以在不进行破坏性更改的情况下进行更改的内容。

或者用Semver的话说:

对任何公共或受保护的内容的更改都应被视为重大更改。 任何新的公开或受保护的内容(至少)都应该是MINOR 只有对任何私有内容的新/更改才能被PATCH

因此,在维护代码方面,注意哪些内容是公开的或受保护的,因为这些是你向用户承诺的内容。

其他回答

又提了一个老问题,但我认为从你所定义的API的角度来考虑这个问题是一个很好的方法。

public——所有标记为public的东西都是API的一部分,任何使用你的类/接口/其他的人都会使用和依赖它。 protected -不要被愚弄了,这也是API的一部分!人们可以子类化,扩展你的代码,使用任何标记为受保护的东西。 private -私有属性和方法可以随心所欲地更改。没有其他人可以使用这些。这些是唯一可以在不进行破坏性更改的情况下进行更改的内容。

或者用Semver的话说:

对任何公共或受保护的内容的更改都应被视为重大更改。 任何新的公开或受保护的内容(至少)都应该是MINOR 只有对任何私有内容的新/更改才能被PATCH

因此,在维护代码方面,注意哪些内容是公开的或受保护的,因为这些是你向用户承诺的内容。

差异如下:

Public:类的任何用户都可以直接访问公共变量或方法。

Protected::受保护的变量或方法不能被类的用户访问,但可以在继承自该类的子类中访问。

Private::私有变量或方法只能从定义它的类内部访问。这意味着不能从扩展该类的子类调用私有变量或方法。

公众:

当你将一个方法(函数)或属性(变量)声明为public时,这些方法和属性可以通过以下方式访问:

声明它的类。 继承上述声明类的类。 这个类之外的任何外部元素也可以访问这些东西。

例子:

<?php

class GrandPa
{
    public $name='Mark Henry';  // A public variable
}

class Daddy extends GrandPa // Inherited class
{
    function displayGrandPaName()
    {
        return $this->name; // The public variable will be available to the inherited class
    }

}

// Inherited class Daddy wants to know Grandpas Name
$daddy = new Daddy;
echo $daddy->displayGrandPaName(); // Prints 'Mark Henry'

// Public variables can also be accessed outside of the class!
$outsiderWantstoKnowGrandpasName = new GrandPa;
echo $outsiderWantstoKnowGrandpasName->name; // Prints 'Mark Henry'

保护:

当将方法(函数)或属性(变量)声明为受保护时,可以通过

声明它的类。 继承上述声明类的类。

外部成员不能访问这些变量。“局外人”的意思是它们不是所声明类本身的对象实例。

例子:

<?php

class GrandPa
{
    protected $name = 'Mark Henry';
}

class Daddy extends GrandPa
{
    function displayGrandPaName()
    {
        return $this->name;
    }

}

$daddy = new Daddy;
echo $daddy->displayGrandPaName(); // Prints 'Mark Henry'

$outsiderWantstoKnowGrandpasName = new GrandPa;
echo $outsiderWantstoKnowGrandpasName->name; // Results in a Fatal Error

准确的错误是这样的:

PHP致命错误:无法访问受保护的属性GrandPa::$name


私人:

当你将一个方法(函数)或属性(变量)声明为私有时,这些方法和属性可以通过以下方式访问:

声明它的类。

外部成员不能访问这些变量。在某种意义上,它们不是已声明类本身的对象实例,甚至不是继承已声明类的类。

例子:

<?php

class GrandPa
{
    private $name = 'Mark Henry';
}

class Daddy extends GrandPa
{
    function displayGrandPaName()
    {
        return $this->name;
    }

}

$daddy = new Daddy;
echo $daddy->displayGrandPaName(); // Results in a Notice 

$outsiderWantstoKnowGrandpasName = new GrandPa;
echo $outsiderWantstoKnowGrandpasName->name; // Results in a Fatal Error

准确的错误消息将是:

注意:Undefined属性:Daddy::$name 致命错误:无法访问私有属性GrandPa::$name


使用反射解剖爷爷类

这个主题并没有超出范围,我在这里添加它只是为了证明反射是非常强大的。正如我在上面三个例子中所述,受保护的和私有的成员(属性和方法)不能在类之外被访问。

然而,有了反射,你甚至可以在类外部访问受保护的和私有的成员。

什么是反射?

反射增加了逆向工程类、接口、 函数、方法和扩展。此外,他们还提供了一些方法 检索函数、类和方法的文档注释。

序言

我们有一个名为Grandpas的类,我们有三个属性。为了便于理解,假设有三个有名字的爷爷:

马克亨利 约翰冲突 将琼斯

让我们将它们(指派修饰符)分别设为public、protected和private。您非常清楚,protected成员和private成员不能在类外部访问。现在让我们用反射来反驳这个说法。

的代码

<?php

class GrandPas   // The Grandfather's class
{
    public     $name1 = 'Mark Henry';  // This grandpa is mapped to a public modifier
    protected  $name2 = 'John Clash';  // This grandpa is mapped to a protected  modifier
    private    $name3 = 'Will Jones';  // This grandpa is mapped to a private modifier
}


# Scenario 1: without reflection
$granpaWithoutReflection = new GrandPas;

# Normal looping to print all the members of this class
echo "#Scenario 1: Without reflection<br>";
echo "Printing members the usual way.. (without reflection)<br>";
foreach($granpaWithoutReflection as $k=>$v)
{
    echo "The name of grandpa is $v and he resides in the variable $k<br>";
}

echo "<br>";

#Scenario 2: Using reflection

$granpa = new ReflectionClass('GrandPas'); // Pass the Grandpas class as the input for the Reflection class
$granpaNames=$granpa->getDefaultProperties(); // Gets all the properties of the Grandpas class (Even though it is a protected or private)


echo "#Scenario 2: With reflection<br>";
echo "Printing members the 'reflect' way..<br>";

foreach($granpaNames as $k=>$v)
{
    echo "The name of grandpa is $v and he resides in the variable $k<br>";
}

输出:

#Scenario 1: Without reflection
Printing members the usual way.. (Without reflection)
The name of grandpa is Mark Henry and he resides in the variable name1

#Scenario 2: With reflection
Printing members the 'reflect' way..
The name of grandpa is Mark Henry and he resides in the variable name1
The name of grandpa is John Clash and he resides in the variable name2
The name of grandpa is Will Jones and he resides in the variable name3

常见的误解:

请不要与下面的例子混淆。正如您仍然可以看到的,如果不使用反射,就不能在类外部访问private和protected成员

<?php

class GrandPas   // The Grandfather's class
{
    public     $name1 = 'Mark Henry';  // This grandpa is mapped to a public modifier
    protected  $name2 = 'John Clash';  // This grandpa is mapped to a protected modifier
    private    $name3 = 'Will Jones';  // This grandpa is mapped to a private modifier
}

$granpaWithoutReflections = new GrandPas;
print_r($granpaWithoutReflections);

输出:

GrandPas Object
(
    [name1] => Mark Henry
    [name2:protected] => John Clash
    [name3:GrandPas:private] => Will Jones
)

调试功能

Print_r、var_export和var_dump是调试器函数。它们以人类可读的形式呈现关于变量的信息。这三个函数将显示PHP 5中对象的受保护属性和私有属性。静态类成员将不会显示。


更多资源:

PHP手册- OOP属性 PHP手册- OOP可见性 PHP类的可见性 Jordizle.com - Public, Private,在PHP 5中受保护


它们允许不同级别的封装

带有抽象示例的可见范围:易于理解

属性或方法的可见性是通过预先声明三个关键字(Public、protected和private)之一来定义的。

Public:如果一个属性或方法被定义为Public,这意味着它可以被任何可以引用对象的对象访问和操作。

文摘。把公众视野想象成任何人都可以参加的“公共野餐”。

Protected:当属性或方法可见性被设置为Protected时,成员只能在类本身和继承类中访问。(继承的:一个类可以拥有另一个类的所有属性和方法)。

将受保护的可见范围视为“公司野餐”,公司成员及其家庭成员不允许进入公众。这是最常见的范围限制。

Private:当一个属性或方法可见性被设置为Private时,只有具有Private成员的类才能访问这些方法和属性(在类内部),不管它们之间可能存在什么类关系。

用野餐做类比,可以把野餐想象成“只允许公司成员参加的公司野餐”。家庭和公众都不行。