ChatGPT解决这个技术问题 Extra ChatGPT

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

何时以及为什么应该在类中使用 publicprivateprotected 函数和变量?它们之间有什么区别?

例子:

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

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

// Protected
protected $variable;
protected function doSomething() {
  // ...
}
我认为这个问题也将受益于使用每个关键字的实际示例的答案,而不是提供每个关键字的字面定义。

M
Mathias Bader

你用:

公共范围以使该属性/方法可在任何地方、对象的其他类和实例中使用。

当您希望您的属性/方法仅在其自己的类中可见时,私有范围。

当您想让您的属性/方法在所有扩展当前类(包括父类)的类中可见时,受保护范围。

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

更多:(获取全面信息)

PHP 手册 - 可见性


protected 范围,当您想让您的变量/函数在扩展当前类及其父类的所有类中可见时。
@Shahid - 我不明白你的意思。任何扩展类 A 的类也扩展了 A 的父类,不是吗?
@JDelage - 请参阅链接 http://www.php.net/manual/en/language.oop5.visibility.php#109324
@Growler 为什么还要费心使用对象呢?
@Growler,一个更有帮助的答案是,尽可能多地隐藏对象的内部工作是很好的。这样它就不太可能破裂。如果您将所有内容都公开,那么另一个程序员可能会更改一个您不希望被对象内部工作以外的任何东西更改的变量。
S
Shankar Narayana Damodaran

https://i.stack.imgur.com/SFysv.jpg

上市:

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

使用反射剖析爷爷类

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

但是,通过反射,您甚至可以通过访问类外的 protectedprivate 成员来实现非凡

那么,什么是反射?

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

前言

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

马克亨利

约翰冲突

威尔琼斯

让我们分别使它们(分配修饰符)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 属性。静态类成员将显示。

更多资源:

PHP 手册 - OOP 属性

PHP 手册 - OOP 可见性

Techflirt.com - PHP 类中的可见性

Jordizle.com - 公共、私有、受 PHP 5 保护


为迟到加入这个车队道歉。你能告诉我为什么有人会使用这些吗?你已经完美地解释了它们是如何工作的等等。我只是想知道使用它们的好处。谢谢
@JamesG 在上面的其他评论中有所解释。 stackoverflow.com/questions/4361553/…
我不知道为什么这可能有点超出这个问题但没有人提到在 PHP 中还有另外两个访问修饰符:abstract 和 final this 关键字只能用于 PHP 类,但它仍然是访问修饰符
我建议您在此处阅读 Dhairya Lakhera 提供的关于抽象的解释:stackoverflow.com/questions/2558559/…。这是对 Shankar Damodaran 解释的完美补充。
U
Udhav Sarvaiya

private - 只能从 WITHIN 类中访问

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

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

这适用于函数和变量。


不确定此处受保护的定义是否正确,从实际选择的答案看来,受保护的 - 只能从继承的类开始访问,不能从原始/父类访问。说“在课堂上”可能有点令人困惑。
我不这么认为,事实上,所选答案似乎是这里令人困惑的答案。见沙希德评论。恕我直言,可以从原始类中很好地访问受保护的方法。
一个班级可以访问另一个班级的公众吗?
@Serjas:不,只有另一个对象,除非它们是静态方法/字段。
我不知道这是否适用于所有编程语言,但在 PHP 中,“受保护”属性/方法可以在声明它的类或从定义属性/方法的类继承的类中访问。
T
The Awnry Bear

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

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

以汽车为例,速度、档位和方向等内容将是私有实例变量。您不希望驾驶员直接操纵空气/燃料比之类的东西。相反,您将有限数量的操作公开为公共方法。汽车的接口可能包括诸如 accelerate()deccelerate()/brake()setGear()turnLeft()turnRight() 等方法。

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

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

编辑:由于您似乎仍在学习面向对象的概念(这比任何语言的语法都更难掌握),我强烈建议您阅读 Matt Zandstra 的 PHP Objects, Patterns, and Practice 的副本。这本书首先教会了我如何有效地使用 OOP,而不仅仅是教我语法。我早在几年前就已经学习了语法,但是如果不了解 OOP 的“原因”,那将毫无用处。


这篇文章编辑推荐的书真的很优秀。到目前为止,我已经证明了这一块非常有启发性。前几章回答了我大部分与课堂相关的问题。
那些让我真正理解对象,而不用不必要的细节来排挤我的思维的书,比如 Smalltalk 中的例子,是 David A Taylor 写的,是面向对象的技术:经理指南和对象技术的业务工程。两者都只有 100 页,每一个都足够简单,可以在一个下午阅读。当然,还有 Gamma 等人的设计模式,尽管基本方法可以简单地用“子类化你想要改变的东西”来描述。
一个非常好的比喻。你有一个受保护的vs私有的吗?
j
jonsca

区别如下:

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

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

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


S
Suman KC

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

属性或方法的这种可见性由三个关键字(公共、受保护和私有)之一的前缀声明定义

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

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

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

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

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

与野餐类比,将野餐视为“仅允许公司成员参加的公司野餐”。不是家庭,也不是一般公众。


T
Techie
/**
 * 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


A
Ahmad Awais

⚡️ 这是一种记住公共、受保护和私有范围的简单方法。

PUBLIC

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

PROTECTED

受保护范围:受保护的变量/函数可用于扩展当前类的所有类。

不!对象无法访问此范围

PRIVATE

私有范围:私有变量/函数仅在定义它的当前类中可见。

不!扩展当前类的类无法访问此范围。

不!对象无法访问此范围。

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


D
DanMan

考虑“何时”:如果我不确定,我倾向于在最初将所有内容声明为私有。原因是,将私有方法公开通常比反过来要容易得多。那是因为您至少可以确定私有方法没有在任何地方使用,而是在类本身中使用。公共方法可能已经在各处使用,可能需要大量重写。

更新:我现在选择默认的 protected,因为我发现它足以封装并且在我扩展类时不会妨碍(我尽量避免)。只有当我有充分的理由使用其他两个时,我才会这样做。

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


随着你的更新:你能更清楚地说明“足够好”和“充分的理由”在这里是如何结合在一起的吗?例如,使用 private 仍然“足够好” 可以使用,但您不建议再使用,尽管您之前给出的理由听起来仍然像一个“好理由”:封装。
@hakre:我们应该努力封装的原因是避免将状态泄漏到外部范围。 protected 已经这样做了,但您可以灵活地进行扩展/继承。同样,除非您有充分的理由将其设为 private
好吧,这可能是我们不同意的一点:protected 实际上会泄漏到外部范围,并且通常会妨碍您,因为它支持错误的设计决策,例如隐式支持继承,而更好地支持组合。这就是为什么除非您有实际要求,否则坚持使用私有通常是开始编写代码的更好方法。这也将防止在实际上还不需要时过早地做出设计决策。
我不会与您的总体观点争论,因为这很公平,但是 protected 不会泄漏到 outer 范围(调用/访问方法/字段的代码),而只会泄漏到内部范围(扩展类)。有区别,对你来说可能很小。跟踪 protected 字段的使用情况比 public 字段的使用情况容易得多。
A
Andrew

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

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

类外的示例用法:

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

Protected:当你想强制其他程序员(和你自己)在访问和设置变量时使用类之外的 getter/setter 时使用它(但你应该保持一致并使用类内部的 getter 和 setter类也是)。这或 private 往往是您应该设置所有类属性的默认方式。

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

类外的示例用法:

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

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

因此,基本上,如果您对属性使用 getter 和 setter(或者如果它仅由父类在内部使用,并且不能在其他任何地方访问),您最好将其设为 private,以防止任何人都不要尝试直接使用它并引入错误

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

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

m
mcfedr

重新提出一个老问题,但我认为考虑这一点的一个非常好的方法是根据您定义的 API。

公共 - 标记为公共的所有内容都是 API 的一部分,任何使用您的类/接口/其他的人都将使用和依赖。

protected - 不要被愚弄,这也是 API 的一部分!人们可以继承、扩展您的代码并使用任何标记为受保护的东西。

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

或者用 Semver 术语:

对任何公共或受保护内容的更改都应视为重大更改。

任何新的公共或受保护的东西都应该(至少)是次要的

只有对任何私有内容的新/更改可以是 PATCH

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


c
code_burgar

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

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


M
Mchl

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


您可能可以稍微充实一下。
D
DPP

PHP 中的变量以三种不同的类型进行转换:

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

私有:这种类型的变量的值只对它所属的类可用。 private $classRoomComputers;

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

protected $familyWealth;


M
Mahedi Hasan Durjoy

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

公共私人保护

https://i.stack.imgur.com/j9RdO.png

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

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

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

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

现在查看表格以了解访问修饰符 阅读全文php access modifire


U
Udhav Sarvaiya

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

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

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


F
Farzana Khan

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

private - 只有当前类才能访问该字段或方法。

protected - 只有这个类的当前类和子类(有时还有同包类)才能访问该字段或方法。

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