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

Ada*_*dam 951 php oop private protected public

何时以及为什么我应该在类中使用public,privateprotected函数和变量?他们之间有什么区别?

例子:

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

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

// Protected
protected $variable;
protected function doSomething() {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

Sar*_*raz 1227

你用:

  • public 范围使该变量/函数可以从对象的任何地方,其他类和实例中获得.

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

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

更多:(如需全面信息)

  • 当你想让你的变量/函数在扩展当前类及其**父类**的所有类中可见时,`protected`范围. (74认同)
  • @Growler,一个更有用的答案是,尽可能隐藏对象的内部工作量是件好事.这样就不太可能破坏.如果你把所有东西都公之于众,那么另一个程序员可能会改变你不希望被对象内部工作以外的任何东西改变的变量. (26认同)
  • @Shahid - 我不明白你的观点.任何扩展A类的类也会扩展A的父类,不是吗? (4认同)
  • @JDelage - 请参阅链接`http:// www.php.net/manual/en/language.oop5.visibility.php#109324` (4认同)
  • @Growler为什么要麻烦使用对象呢? (4认同)
  • 没有"对象的实例"这样的东西.只有"类的实例",它是一个对象.请编辑你的答案. (2认同)
  • “包括父类”是恕我直言的误导-它应该是“包括类本身” (2认同)

Sha*_*ran 1145

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'
Run Code Online (Sandbox Code Playgroud)

保护:

当您声明方法(函数)或属性(变量)时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
Run Code Online (Sandbox Code Playgroud)

确切的错误是这样的:

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
Run Code Online (Sandbox Code Playgroud)

确切的错误消息将是:

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


反射解剖爷爷班

这个主题并没有真正超出范围,我在这里添加它只是为了证明反射真的很强大.正如我在上面三个实施例所指出的,protectedprivate构件(属性和方法)不能在类的外部访问.

然而,随着反射,你可以做的超乎寻常的甚至访问protectedprivate外部类的成员!

好吧,什么是反思?

Reflection增加了对类,接口,函数,方法和扩展进行反向工程的能力.此外,它们还提供了检索函数,类和方法的文档注释的方法.

前言

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

  • 马克亨利
  • 约翰克拉什
  • 威尔琼斯

让我们让他们(分配调节剂)public,protectedprivate分别.你很清楚,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>";
}
Run Code Online (Sandbox Code Playgroud)

输出:

#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
Run Code Online (Sandbox Code Playgroud)

常见的误解:

请不要与下面的例子混淆.您仍然可以看到,如果不使用反射,则无法在类外部访问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);
Run Code Online (Sandbox Code Playgroud)

输出:

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

调试功能

print_r,var_export并且var_dump调试器功能.它们以人类可读的形式呈现有关变量的信息.这三个函数将揭示protectedprivate将与PHP 5.静态类成员对象的属性被显示.


更多资源:


  • 为什么要读这些文字..当图片说明了一切时;) (2认同)

The*_*ear 82

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

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

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

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

此方法还允许您在不破坏接口与客户端代码的契约的情况下更改和改进类中公共方法的实现.例如,您可以改进accelerate()方法以提高燃油效率,但该方法的使用将保持不变; 客户端代码不需要更改,但仍然可以获得效率提升的好处.

编辑:由于你似乎还在学习面向对象的概念(比任何语言的语法都难以掌握),我强烈建议你选择Matt Zandstra 的PHP对象,模式和实践的副本.这本书首先教我如何有效地使用OOP,而不仅仅是教我语法.我事先已经学会了语法,但如果不理解OOP的"为什么",那就没用了.

  • 在这篇文章的编辑推荐的书非常非常好.到目前为止,我发现的这一块很有启发性.前几章回答了我课堂相关的大部分问题. (3认同)

Ola*_*laf 78

private - 只能从课堂上访问

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

public - 也可以从代码OUTSIDE类访问

这适用于函数和变量.

  • 我不这么认为,事实上似乎选定的答案是令人困惑的答案.见Shahids评论.恕我直言,可以从原始类中访问受保护的方法. (7认同)

小智 25

区别如下:

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

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

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


Sum*_*K.C 17

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

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

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

  • 抽象例如.将公众可见范围视为任何人都可以参加的"公共野餐".

受保护:当属性或方法可见性设置为受保护成员时,只能在类本身以及继承和继承类中进行访问.(继承: - 一个类可以拥有另一个类的所有属性和方法).

  • 将公众成员及其家庭成员视为"公司野餐",将其视为受保护的可见范围.这是最常见的范围限制.

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

  • 与野餐类比,在野餐时认为是"公司野餐,只允许公司成员".不是家庭,也不允许普通公众.


Tec*_*hie 15

/**
 * 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
Run Code Online (Sandbox Code Playgroud)

摘自 :

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


Ahm*_*ais 11

⚡️这是一个容易记住范围的方法public,protectedprivate.

PUBLIC:

  • public scope:公共变量/函数可用于对象和其他类.

PROTECTED:

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

PRIVATE:

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

阅读PHP手册中方法或变量的可见性.


Dan*_*Man 9

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

更新:我protected现在是默认的,因为我发现它足够封装,并且在我扩展类时不会妨碍(我试图避免这种情况).只有我有充分的理由使用其他两个,我才会.

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

  • 随着你的更新:你能更清楚地说"好"和"好理由"在一起怎么样?例如,使用`private`仍然可以*"足够好"*使用,但你不建议再使用早期的原因,你仍然给出声音"好理由":封装. (3认同)

cod*_*gar 6

PHP手册中对这个问题很好看这里.

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


And*_*rew 6

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

公共:如果您可以直接从代码中的任何位置访问和更改此变量,请使用此选项.

来自课外的示例用法:

$myObject = new MyObject()
$myObject->publicVar = 'newvalue';
$pubVar = $myObject->publicVar;
Run Code Online (Sandbox Code Playgroud)

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

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

来自课外的示例用法:

$myObject = new MyObject()
$myObject->setProtectedVar('newvalue');
$protectedVar = $myObject->getProtectedVar();
Run Code Online (Sandbox Code Playgroud)

私有:private属性与protected属性非常相似.但区别的特征/区别在于,如果private不使用父类的getter或setter ,它也会使子类无法访问.

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

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

$this->setPrivateVar('newvalue');
$privateVar = $this->getPrivateVar();
Run Code Online (Sandbox Code Playgroud)


mcf*_*edr 6

重温一个老问题,但我认为考虑这个问题的一个很好的方法是根据您定义的 API。

  • public - 所有标记为 public 的东西都是 API 的一部分,任何使用你的类/接口/其他的人都会使用和依赖。

  • protected- 不要上当,这也是 API 的一部分!人们可以子类化,扩展您的代码并使用任何标记为受保护的东西。

  • private- 私有属性和方法可以随心所欲地更改。没有其他人可以使用这些。这些是您可以在不进行重大更改的情况下进行更改的唯一内容。

或者用Semver术语来说:

  • 对任何事物的更改publicprotected应被视为重大更改。

  • 任何新的publicprotected应该(至少)次要的

  • 只有对任何东西的新/更改private才能打补丁

因此,在维护代码方面,最好小心您所做的事情,public或者protected因为这些是您向用户承诺的事情。


Mch*_*chl 5

它们在那里允许不同级别的封装

  • 你可能可以稍微充实一下。 (11认同)