公共、私人和受保护之间的区别是什么?

什么时候,为什么我应该在一个类中使用publicprivateprotected函数和变量?它们之间的区别是什么?

例子:

// Publicpublic $variable;public function doSomething() {// ...}
// Privateprivate $variable;private function doSomething() {// ...}
// Protectedprotected $variable;protected function doSomething() {// ...}
593690 次浏览

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

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

private -只能从类内部访问

protected -可以从类内部和继承类中访问

public -也可以从类外的代码访问

这不仅适用于变量,也适用于函数。

你使用:

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

  • 当您希望您的属性/方法仅在其自己的类中可见时,

    private范围。

  • protected范围当你想让你的属性/方法在所有扩展当前类的类中可见,包括父类。

如果你不使用任何可见性修饰符,属性/方法将是公共的。

更多:(全面信息)

< p >考虑“# 0”:< br >如果我不太确定,我倾向于一开始就把所有东西都声明为私有。原因是,将私有方法转换为公共方法通常比将私有方法转换为公共方法容易得多。这是因为您至少可以确定private方法除了在类本身中没有在其他地方使用过。一个公共方法可能已经在各处使用,可能需要大量重写

更新:我现在使用默认值protected,因为我发现它对于封装来说已经足够好了,并且不会妨碍我扩展类(这是我尽量避免的)。只有当我有充分的理由使用另外两个时,我才会使用。

使用private方法的一个很好的理由是,它实现了该对象固有的一些东西,即使是扩展类也不应该更改(事实原因,除了封装之外,比如内部状态管理)。最终,它仍然很容易追踪到protected方法通常被使用的地方,所以我现在默认使用protected。我承认,也许不是百分百客观的“战壕”经验。

差异如下:

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

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

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

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

如果你“为接口而不是实现编码”,那么做出可见性决策通常是相当简单的。一般来说,变量应该是私有的或受保护的,除非您有充分的理由公开它们。使用公共访问器(getter /setter)来限制和规范对类内部的访问。

以汽车为例,速度、档位和方向等都是私有实例变量。你不希望司机直接操纵像空气/燃料比这样的事情。相反,您将有限数量的操作公开为公共方法。汽车的接口可能包括accelerate()deccelerate()/brake()setGear()turnLeft()turnRight()等方法。

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

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

编辑:既然你似乎还在学习面向对象的概念(这比任何语言的语法都要难掌握得多),我高度建议你读一下Matt Zandstra的PHP对象、模式和实践。这本书第一次教会了我如何有效地使用OOP,而不仅仅是教我语法。我在几年前就已经学过语法了,但如果不理解OOP的“原因”,这是没有用的。

PHP中的变量有三种类型:

Public:此变量类型的值在所有作用域可用,并在执行代码时调用。声明:public $examTimeTable;

Private:此类型变量的值仅在它所属的类上可用。# 0 < / p >

Protected:该类的值仅且仅在以继承或其子类的形式授予Access时可用。通常使用::授予父类访问权限

# 0

/*** 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; // Worksecho $obj->protected; // Fatal Errorecho $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 privateprotected $protected = 'Protected2';
function printHello(){echo $this->public;echo $this->protected;echo $this->private;}}
$obj2 = new MyClass2();echo $obj2->public; // Worksecho $obj2->private; // Undefinedecho $obj2->protected; // Fatal Error$obj2->printHello(); // Shows Public, Protected2, Undefined

摘录自:

http://php.net/manual/en/language.oop5.visibility.php < a href = " http://php.net/manual/en/language.oop5.visibility.php " > < / >

能见度范围抽象的例子::容易理解

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

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

  • 文摘。把公众能见度的范围视为任何人都可以达到的“公共野餐”

保护:当一个属性或方法的可见性被设置为受保护的成员只能在类本身和继承&继承类。(继承的:一个类可以拥有另一个类的所有属性和方法)。

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

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

  • 用野餐的比喻,在野餐中想象一个0号。家庭和公众都不行。

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时,这些方法和属性可以由

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

外部成员不能访问这些变量。“局外人”的意思是他们不是0

例子:

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


使用< >强反射< / >强解剖爷爷类

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

然而,使用反射,你甚至可以通过访问类外部的# 0# 1成员来实现优秀 !

什么是反射?

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

序言

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

  • 马克亨利
  • 约翰冲突
  • 将琼斯

让我们把它们分别设为publicprotectedprivate。您非常清楚,protectedprivate成员不能在类之外访问。现在让我们用反射来反驳这个说法。

的代码

<?php
class GrandPas   // The Grandfather's class{public     $name1 = 'Mark Henry';  // This grandpa is mapped to a public modifierprotected  $name2 = 'John Clash';  // This grandpa is mapped to a protected  modifierprivate    $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 classecho "#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 reflectionPrinting members the usual way.. (Without reflection)The name of grandpa is Mark Henry and he resides in the variable name1
#Scenario 2: With reflectionPrinting members the 'reflect' way..The name of grandpa is Mark Henry and he resides in the variable name1The name of grandpa is John Clash and he resides in the variable name2The 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 modifierprotected  $name2 = 'John Clash';  // This grandpa is mapped to a protected modifierprivate    $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_dump调试器功能。它们以人类可读的形式呈现关于变量的信息。这三个函数将显示PHP 5中对象的protectedprivate属性。静态类成员将显示


更多资源:


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

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

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

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

公共:当您可以在代码中的任何地方直接访问和更改该变量时,使用此方法。

类外部的示例用法:

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

受保护的:当你想强迫其他程序员(和你自己)在访问和设置变量时在类外使用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的范围。

# 1:

  • public作用域:公共变量/函数对对象和其他类都可用。

# 1:

  • protected作用域:受保护的变量/函数可用于扩展当前类的所有类。
  • 不!对象不能访问此作用域

# 1:

  • private作用域:私有变量/函数只在定义它的当前类中可见。
  • 不!扩展当前类的类不能访问此作用域。
  • 不!对象不能访问此作用域。

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

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

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

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

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

或者在Semver中:

  • 任何publicprotected的更改都应该被认为是重大更改。

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

  • 只有对任何private的新/更改才能被PATCH

因此,在维护代码方面,最好注意你把什么东西设为publicprotected,因为这些是你向用户承诺的东西。

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

private -只有当前类可以访问字段或方法。

protected——只有这个类的当前类和子类(有时也包括同包类)可以访问该字段或方法。

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