公共,私人和保护之间有什么区别?

何时以及为什么要在课堂中使用publicprivateprotected函数和variables? 他们有什么区别?

例子:

 // Public public $variable; public function doSomething() { // ... } // Private private $variable; private function doSomething() { // ... } // Protected protected $variable; protected function doSomething() { // ... } 

你用:

  • public范围,使该variables/函数可以在任何地方,对象的其他类和实例中使用。

  • private范围,当你希望你的variables/函数只能在自己的类中可见。

  • 当你想让你的variables/函数在扩展包括父类的当前类的所有类中都可见时。

更多:(全面的信息)

dd

上市:

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

  • 宣布它的同一个类。
  • inheritance上面声明的类的类。
  • 这个class级以外的任何外国人也可以访问这些东西。

例:

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

保护:

当你声明一个方法(函数)或属性(variables)被protected ,这些方法和属性可以被访问

  • 宣布它的同一个类。
  • inheritance上面声明的类的类。

局外人成员不能访问这些variables。 “局外人”是指他们不是被声明的类本身的对象实例。

例:

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


私人的:

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

  • 宣布它的同一个类。

局外人成员不能访问这些variables。 局外人的意义在于它们不是被声明的类本身的对象实例,甚至是inheritance了被声明的类的类。

例:

 <?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来解剖爷爷级

这个主题并没有超出范围,我在这里添加它只是为了certificatereflection是非常强大的。 正如我在上面的三个例子中所说的那样, protectedprivate成员(属性和方法)不能在class级之外访问。

但是,通过反思,您甚至可以在课堂之外访问protectedprivate成员,从而做到超乎寻常的事情!

那么,什么是反思?

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

前言

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

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

让我们分别将它们(分配修饰符)设置为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成员不能在没有使用reflection的情况下在课堂之外访问

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

debuggingfunction

print_rvar_exportvar_dump是debugging器函数 。 他们以可读的forms呈现有关variables的信息。 这三个函数将使用PHP 5揭示对象的protected属性和private属性。静态类成员将不会显示。


更多资源:

  • PHP手册 – OOP属性
  • PHP手册 – OOP可见性
  • Techflirt.com – PHP类中的可见性
  • Jordizle.com – 公共,私人,受PHP 5保护
  • Tuxradar.com – 公共,私人和受保护的

通常认为这是一种很好的做法,即默认所需的最低可见度,因为这可以促进数据封装和良好的接口devise。 在考虑成员variables和方法可见性时,考虑成员在与其他对象的交互中扮演的angular色。

如果你“编写了一个接口而不是实现”,那么做出可视化决策通常是非常简单的。 一般来说,variables应该是私人的或保护的,除非你有充分的理由去揭露它们。 使用公共访问器(getters / setter)来限制和pipe理对类内部的访问。

以汽车为例,速度,档位和方向等都是私人实例variables。 你不希望驾驶员直接操纵空气/燃料比例。 相反,您将公开的方法公开为数有限的操作。 汽车的接口可能包括accelerate()deccelerate() / brake()setGear()turnLeft()turnRight()等方法。

司机不知道也不应该关心汽车内部如何执行这些动作,并且暴露出该function可能对司机和其他人造成危险。 因此,devise一个公共接口和封装这个接口后面的数据是一个很好的实践。

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

编辑:由于看起来你还处于学习面向对象的概念(比任何语言的语法都要困难得多),所以我强烈build议你拿起一份由Matt Zandstra提供的PHP Objects,Patterns和Practice的副本。 这是首先教给我如何有效地使用面向对象的书,而不仅仅是教给我语法。 我已经事先了解了几年的语法,但是没有理解OOP的“为什么”,这是毫无用处的。

私人 – 只能在课堂内进行访问

保护 – 可以从类和INHERITING类中进行访问

公共 – 也可以从课堂外的代码访问

这适用于函数以及variables。

区别如下:

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

Protected ::受保护的variables或方法不能由类的用户访问,但可以在从类inheritance的子类中访问。

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

可视范围抽象示例 :: 易于理解

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

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

  • 摘要例如。 把公众的视野范围想象成任何人都可以来的“公共野餐”

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

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

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

  • 野餐比喻认为是“只有公司成员才可以野餐的公司野餐”。 不是家庭,也不是公众。
 /** * 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

PHP手册在这里有一个很好的阅读问题。

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

考虑“何时”:
如果我不确定的话,我倾向于把所有的东西都宣布为私有。 原因是,将私有方法公开化比其他方式更容易。 那是因为你至less可以确定这个私有方法没有被用在任何地方,而是在这个类中。 公开的方法可能已经在各处使用,可能需要大量的重写。

更新:我去现在默认的protected ,因为我来发现这是足够好的封装,并没有阻碍,当我扩展类(我试图避免反正)。 只有当我有充分的理由使用其他两个,我会的。

private方法的一个很好的理由是实现该对象固有的东西,即使是扩展的类也不应该改变(事实上的原因,除了封装外)。 最终,通过追踪protected方法通常还是很容易的,所以我现在默认protected 。 我承认,在“战壕”体验中,也许不是100%客观的。

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

PHP中的variables分为三种types:

Public:这个variablestypes的值在所有范围内都可用,并且调用执行你的代码。 声明为: public $examTimeTable;

私有:这种types的variables的值只能用于它所属的类。 private $classRoomComputers;

受保护:仅适用于此类的值,只有在以inheritanceforms或其子类授予Access后才可用。 一般用于::授予父类的访问权限

protected $familyWealth;

对我而言,这是了解这三种属性types最有用的方法:

公开 :当你确定这个variables被直接访问并从你的代码中的任何地方改变的时候使用它。

从课外使用的示例:

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

受保护的 :当你想要强迫其他程序员(和你自己)在访问和设置variables时使用getter / setter(但是你应该保持一致并且在类中使用getter和setter)的时候使用它。 这个或private往往是你应该设置所有类属性的默认方式。

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

从课外使用的示例:

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

私人private物业与protected物业非常相似。 但是区别特征/区别在于,将它private也使得子类无法访问,而不使用父类的getter或setter。

所以基本上,如果你正在使用getter和setter作为一个属性(或者如果它只在父类内部使用,并不意味着可以在其他地方访问),你也可以把它设置为private ,以防止任何人试图直接使用它并引入错误

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

 $this->setPrivateVar('newvalue'); $privateVar = $this->getPrivateVar(); 

这是一个简单的方法来记住publicprotectedprivate的范围。

PUBLIC

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

PROTECTED

  • protected范围:受保护的variables/函数可用于扩展当前类的所有类。
  • 没有! 对象不能访问这个范围

PRIVATE

  • private范围:私有variables/function只在当前定义的类中可见。
  • 没有! 扩展当前类的类不能访问此作用域。
  • 没有! 对象不能访问这个范围。

阅读PHP手册上的方法或variables的可见性 。

复兴一个老问题,但我认为一个真正好的方法来思考这个问题是根据您定义的API。

  • public – 标记为public的所有内容都是API的一部分,任何使用你的class / interface / other的人都将使用并依赖它。

  • protected – 不要被愚弄,这也是API的一部分! 人们可以inheritance,扩展你的代码并使用任何标记为protected的东西。

  • private – 私人财产和方法可以改变,只要你喜欢。 没有人可以使用这些。 这些是唯一可以改变的东西,而不用做出重大改变。

或者用Semver的话来说:

  • publicprotected进行的更改应视为主要更改。

  • 任何新的publicprotected应该(至less)MINOR

  • 只有新的/改变任何private可以PATCH

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

Public:当你声明一个variables或方法时,是一个默认状态,可以通过任何东西直接访问该对象。

受保护:只能在对象和子类中访问。

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