public,private和protected之间有什么区别?

时间:2010-12-05 22:13:14

标签: php oop private public protected

我何时以及为什么要在课程中使用publicprivateprotected函数和变量?他们之间有什么区别?

示例:

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

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

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

18 个答案:

答案 0 :(得分:1191)

您使用:

  • public范围,可以从对象的任何位置,其他类和实例中获取该变量/函数。

  • private范围当您希望变量/函数仅在其自己的类中可见时。

  • protected范围当您想要在扩展当前类(包括父类)的所有类中显示您的变量/函数时。

更多:(有关综合信息)

答案 1 :(得分:1112)

dd

公开:

当您将方法(函数)或属性(变量)声明为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'

受保护的:

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

访问这些方法和属性
  • 宣布它的同一个类。
  • 继承上述声明的类的类。

局外人无法访问这些变量。 “局外人”,因为他们不是声明类本身的对象实例。

示例:

<?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


私人:

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

  • 宣布它的同一个类。

局外人无法访问这些变量。局外人认为他们不是声明类本身的对象实例,甚至是继承声明的类的类。

示例:

<?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

确切的错误消息将是:

  

注意:未定义的属性:Daddy :: $ name
  致命错误:无法访问私人财产GrandPa :: $ name


使用Reflection

解析爷爷班级

这个主题并没有真正超出范围,我在这里添加它只是为了证明反射真的很强大。正如我在上面三个示例中所述,protectedprivate成员(属性和方法)无法在类外部访问。

但是,通过反思,您甚至可以访问 protected private 成员来执行 extra-ordinary 课外!

嗯,什么是反思?

  

Reflection增加了逆向工程类,接口,   功能,方法和扩展。此外,他们提供了方法   检索函数,类和方法的doc注释。

序言

我们有一个名为Grandpas的类,并说我们有三个属性。为了便于理解,请考虑有三个名字的爷爷:

  • Mark Henry
  • John Clash
  • Will Jones

让我们分别制作它们(分配修饰符)publicprotectedprivate。您非常清楚,protectedprivate成员无法在课堂外访问。现在让我们反驳使用反射的陈述。

代码

<?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

常见的误解:

请不要与以下示例混淆。您仍然可以看到,privateprotected成员无法在不使用反射的情况下访问

<?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_rvar_exportvar_dumpdebugger functions。它们以人类可读的形式呈现有关变量的信息。这三个函数将使用PHP 5显示对象的protectedprivate属性。静态类成员将显示。


更多资源:


答案 2 :(得分:82)

通常认为默认为所需的最低可见性是一种良好做法,因为这可以促进数据封装和良好的界面设计。在考虑成员变量和方法可见性时,请考虑成员在与其他对象的交互中扮演的角色。

如果您“编写接口而不是实现”,则通常可以非常直接地做出可见性决策。通常,变量应该是私有的或受保护的,除非您有充分的理由公开它们。使用公共访问者(getters / setters)来限制和规范对类内部的访问。

使用汽车作为类比,速度,齿轮和方向等内容将是私有实例变量。您不希望驾驶员直接操纵空气/燃料比等事物。相反,您将有限数量的操作公开为公共方法。汽车界面可能包括accelerate()deccelerate() / brake()setGear()turnLeft()turnRight()等方法。

司机不知道也不应该关心这些行动是如何由汽车的内部实施的,并且暴露该功能可能对驾驶员和其他人在路上造成危险。因此,设计公共接口并将数据封装在该接口后面的良好实践。

这种方法还允许您改变和改进类中公共方法的实现,而不会破坏接口与客户端代码的契约。例如,您可以改进accelerate()方法以提高燃油效率,但该方法的使用将保持不变;客户端代码不需要更改,但仍可以提高效率。

编辑:由于您似乎还在学习面向对象的概念(比任何语言的语法都难以掌握),我高度推荐拿起Matt Zandstra的 PHP对象,模式和实践的副本。这本书首先教我如何有效地使用OOP,而不仅仅是教我语法。我事先已经学会了语法,但如果没有理解OOP的“原因”,那就毫无用处。

答案 3 :(得分:75)

private - 只能从课堂上的WITHIN访问

protected - 可以从WITHIN类和INHERITING类中访问

public - 可以从类OUTSIDE中访问

这适用于函数和变量。

答案 4 :(得分:25)

区别如下:

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

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

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

答案 5 :(得分:16)

可见性范围抽象示例 :: 轻松理解

通过预先修复三个关键字(公共,受保护和私有)之一的声明来定义属性或方法的可见性

公开:如果属性或方法被定义为公共,则意味着它可以被任何可以引用对象的内容访问和操纵。

  • 摘要例如。将公众可见范围视为任何人都可以来的“公共野餐”

受保护:当属性或方法可见性设置为受保护成员时,只能在类本身内进行访问,并且可以通过继承&amp;继承类。 (继承: - 一个类可以拥有另一个类的所有属性和方法。)

  • “公司野餐”视为受保护的可见范围,公司成员及其家庭成员不得公开。这是最常见的范围限制。

私有:当属性或方法可见性设置为private时,只有具有私有成员的类才能访问这些方法和属性(在类内部),尽管有类关系也许

  • 与野餐类比,认为是一个“公司野餐,只允许公司成员”在野餐。不允许一般公众进入家庭。

答案 6 :(得分:14)

/**
 * Define 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; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Shows Public, Protected and Private


/**
 * Define MyClass2
 */
class MyClass2 extends MyClass
{
    // We can redeclare the public and protected method, but not private
    protected $protected = 'Protected2';

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

$obj2 = new MyClass2();
echo $obj2->public; // Works
echo $obj2->private; // Undefined
echo $obj2->protected; // Fatal Error
$obj2->printHello(); // Shows Public, Protected2, Undefined

摘自:

http://php.net/manual/en/language.oop5.visibility.php

答案 7 :(得分:11)

  

⚡️以下是记住publicprotectedprivate范围的简便方法。

<强> PUBLIC

  • public范围:公共变量/函数可用于对象和其他类。

<强> PROTECTED

  • protected范围:受保护的变量/函数可用于扩展当前类的所有类。
  • 没有!对象无法访问此范围

<强> PRIVATE

  • private范围:私有变量/函数仅在定义它的当前类中可见。
  • 没有!扩展当前类的类无法访问此范围。
  • 没有!对象无法访问此范围。

阅读PHP手册上的方法或变量的Visibility

答案 8 :(得分:8)

考虑'何时':
如果我不确定的话,我倾向于最初声明一切都是私人的。原因是,将私有方法公开比通过其他方式更容易。那是因为你至少可以确定私有方法没有在类本身的任何地方使用过。公共方法可能已经在任何地方使用,可能需要进行大量的重写。

更新:我现在的默认值为protected,因为我发现它对封装来说已经足够好了,并且当我没有时就不会妨碍扩展课程(我试图避免)。只有我有充分的理由使用其他两个,我才会。

private方法的一个很好的理由是实现该对象固有的东西,即使扩展类也不应该改变(事实上的原因,除了封装,如内部状态管理)。最终,通常很容易找到通常使用protected方法的位置,所以我现在默认为protected。我承认,也许不是100%客观的“在战壕中”的经历。

答案 9 :(得分:6)

PHP手册对问题here有很好的解读。

  

可以通过在声明前加上关键字public,protected或private来定义属性或方法的可见性。声明为public的类成员可以随处访问。声明受保护的成员只能在类本身以及继承和父类中访问。声明为private的成员只能由定义该成员的类访问。

答案 10 :(得分:6)

对我来说,这是理解这三种属性类型的有用的方式:

公开:当您可以直接从代码中的任何位置访问和更改此变量时,请使用此选项。

来自课外的示例用法:

$myObject = new MyObject()
$myObject->publicVar = 'newvalue';
$pubVar = $myObject->publicVar;

受保护:当您想要强制其他程序员(和您自己)在访问和设置变量时使用类外的getter / setter时使用此选项(但您应该保持一致并使用getter和班上的人也是如此)。这个或private往往是您应该设置所有类属性的默认方式。

为什么呢?因为如果您在将来的某个时刻(甚至可能在5分钟内)决定您想要操作为该属性返回的值或在获取/设置之前对其执行某些操作,您可以在不重构任何地方的情况下执行此操作在你的项目中使用它。

来自课外的示例用法:

$myObject = new MyObject()
$myObject->setProtectedVar('newvalue');
$protectedVar = $myObject->getProtectedVar();

私有private属性与protected属性非常相似。但区别的特征/区别在于,使private使其无法使用父类的getter或setter而无法访问子类。

所以基本上,如果你正在为一个属性使用getter和setter(或者如果它只在父类内部使用它并且它不能在其他任何地方访问)你也可以使它{{ 1}},只是为了防止任何人试图直接使用它并引入错误

子类(扩展MyObject)中的示例用法:

private

答案 11 :(得分:4)

PHP中的变量有三种不同的类型:

公共:此变量类型的值在所有范围内都可用,并在执行代码时调用。 声明为:public $examTimeTable;

Private:此类变量的值仅适用于它所属的类。  private $classRoomComputers;

受保护:仅此类的值,仅在以继承形式或其子类授予Access时可用。通常使用::授予父类

的访问权限

protected $familyWealth;

答案 12 :(得分:4)

他们允许不同级别的encapsulation

答案 13 :(得分:3)

复兴一个旧问题,但我认为考虑这个问题的一个非常好的方法就是你所定义的API。

  • public - 所有标记为公开的内容都是使用您的类/接口/其他人使用和依赖的API的一部分。

  • protected - 不要被愚弄,这也是API的一部分!人们可以子类化,扩展代码并使用任何标记为受保护的内容。

  • private - 可以根据需要更改私有属性和方法。没有人可以使用这些。这些是您可以在不进行重大更改的情况下更改的唯一内容。

Semver条款:

  • 对任何publicprotected的更改都应视为主要更改。

  • 新的publicprotected应该是(至少)MINOR

  • 只有private的新内容/更改可以是PATCH

因此,在维护代码方面,谨慎对待您所做的事情publicprotected,因为这些是您向用户承诺的事情。

答案 14 :(得分:1)

Public:声明变量或方法时是默认状态,任何东西都可以直接访问该对象。

Protected:只能在对象和子类中访问。

Private:只能在对象中引用,而不能在子类中引用。

答案 15 :(得分:1)

当我们在项目中遵循面向对象的php时,我们应遵循一些规则以在php中使用访问修饰符。今天,我们将清楚地了解什么是访问修饰符以及如何使用它。PHP访问修饰符用于设置PHP类及其成员(这些成员是在类范围内定义的函数和变量)的访问权限。在php中,类成员有三个作用域。

  1. 公共
  2. PRIVATE
  3. 受保护的

现在,让我们看一下下面的图片,以了解访问修饰符的访问级别 enter image description here

现在,让我们看一下下面的列表,以了解可能用作访问修饰符的PHP关键字。

public:-类或使用此访问修饰符定义的成员可以从任何地方公开访问,甚至可以从类范围之外访问。

private:-具有此关键字的类成员将在类本身内访问。我们无法从子类访问私有数据。它保护成员免受外部类访问。

protected:-与private相同,除了允许子类访问受保护的超类成员。

现在请参阅下表以了解访问修饰符阅读完整的文章php access modifire

答案 16 :(得分:0)

您使用:

  • public范围使该属性/方法可从任何位置,对象的其他类和实例使用。

  • 如果您希望属性/方法仅在其自己的类中可见,请使用
  • private范围。

  • 要在所有扩展当前类(包括父类)的类中使属性/方法可见时,请使用
  • protected范围。

更多 :(有关全面信息)

答案 17 :(得分:0)

提到的关键字是访问修饰符,可帮助我们实现封装(或信息隐藏)。它们告诉编译器哪些其他类应该可以访问所定义的字段或方法。

private-仅当前类有权访问该字段或方法。

受保护的-只有此类的当前类和子类(有时甚至是相同包装的类)才能访问该字段或方法。

public-任何类都可以引用该字段或调用该方法。