В чем разница между публичным, частным и защищенным?

924

Когда и почему следует использовать public, private и protected функции и переменные внутри класса? В чем разница между ними?

Примеры:

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

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

// Protected
protected $variable;
protected function doSomething() {
  // ...
}
  • 50
    Я думаю, что этот вопрос также выиграл бы от ответов с практическими примерами использования каждого вместо предоставления буквального определения того, что делает каждое ключевое слово.
  • 56
    Я действительно считаю, что этот вопрос должен быть публичным, а не защищенным.
Теги:
oop
private
public
protected

16 ответов

1086
Лучший ответ

Ты используешь:

  • public область видимости, чтобы сделать эту переменную/функцию доступной из любого места, других классов и экземпляров объекта.

  • private область, когда вы хотите, чтобы ваша переменная/функция была видна только в своем собственном классе.

  • protected область, когда вы хотите сделать вашу переменную/функцию видимой во всех классах, которые расширяют текущий класс, включая родительский класс.

Подробнее: (для полной информации)

  • 70
    protected область, когда вы хотите сделать вашу переменную / функцию видимой во всех классах, которые расширяют текущий класс И его родительские классы .
  • 4
    @Shahid - я не понимаю вашу точку зрения. Любой класс, который расширяет класс A, также расширяет родительский класс A, нет?
Показать ещё 7 комментариев
1017

Изображение 723

Общественность:

Когда вы объявляете метод (функцию) или свойство (переменную) как 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

Точные сообщения об ошибках будут:

Примечание: неопределенное свойство: папа :: $ name
Неустранимая ошибка: невозможно получить доступ к частной собственности GrandPa :: $ name


Рассекая Дедушку с помощью отражения

Эта тема на самом деле не выходит за рамки, и я добавляю ее сюда, чтобы доказать, что рефлексия действительно мощная. Как я уже говорил в трех приведенных выше примерах, protected и private члены (свойства и методы) не могут быть доступны за пределами класса.

Тем не менее, с отражением вы можете сделать экстраординарное, даже имея доступ к protected и private членам вне класса!

Ну что такое отражение?

Отражение добавляет возможность обратного проектирования классов, интерфейсов, функций, методов и расширений. Кроме того, они предлагают способы получения комментариев к документам для функций, классов и методов.

преамбула

У нас есть класс с именем Grandpas и говорят, что у нас есть три свойства. Для простоты рассмотрим три дедушки с именами:

  • Марк Генри
  • Джон Клаш
  • Уилл Джонс

Давайте сделаем их (назначить модификаторы) public, protected и private соответственно. Вы очень хорошо знаете, что protected и private члены не могут быть доступны вне класса. Теперь давайте противоречим утверждению, используя отражение.

Код

<?php

class GrandPas   // The Grandfather 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

Распространенные заблуждения:

Пожалуйста, не путайте с приведенным ниже примером. Как вы все еще можете видеть, private и protected члены не могут быть доступны вне класса без использования отражения.

<?php

class GrandPas   // The Grandfather 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_r, var_export и var_dump являются функциями отладчика. Они представляют информацию о переменной в удобочитаемой форме. Эти три функции покажут protected и private свойства объектов в PHP 5. Статические члены класса не будут показаны.


Больше ресурсов:


  • 0
    извинения за опоздание добавить на этот конво. Можете ли вы сказать мне, почему кто-то будет использовать их? Вы прекрасно объяснили, как они работают и т.д. Я просто хотел бы узнать о преимуществах использования каждого из них. Спасибо
  • 0
    @JamesG это немного объяснено в другом комментарии выше. stackoverflow.com/questions/4361553/...
Показать ещё 2 комментария
78

Обычно считается, что для обычной работы по умолчанию требуется минимальная видимость, поскольку это способствует инкапсуляции данных и хорошему дизайну интерфейса. При рассмотрении видимости элементов и видимости метода думайте о роли, которую член играет во взаимодействии с другими объектами.

Если вы "кодируете интерфейс, а не реализацию", тогда обычно довольно легко принимать решения о видимости. В общем, переменные должны быть частными или защищенными, если у вас нет веских оснований для их раскрытия. Вместо этого используйте общедоступные средства доступа (getters/seters), чтобы ограничить и регулировать доступ к внутренним классам.

Чтобы использовать автомобиль в качестве аналогии, такие вещи, как скорость, передача и направление, будут частными переменными экземпляра. Вы не хотите, чтобы водитель напрямую манипулировал такими вещами, как соотношение воздух/топливо. Вместо этого вы публикуете ограниченное количество действий в качестве общедоступных методов. Интерфейс к машине может включать такие методы, как accelerate(), deccelerate()/brake(), setGear(), turnLeft(), turnRight() и т.д.

Водитель не знает и не должен заботиться о том, как эти действия выполняются внутренними компонентами автомобиля, и подвергая эту функциональность опасным для водителя и других людей на дороге. Следовательно, хорошая практика разработки публичного интерфейса и инкапсуляция данных за этим интерфейсом.

Этот подход также позволяет вам изменять и улучшать реализацию общедоступных методов в вашем классе, не нарушая контракт с клиентским кодом. Например, вы можете улучшить метод accelerate(), чтобы быть более экономичным, но использование этого метода останется прежним; клиентский код не требует никаких изменений, но по-прежнему пользуется преимуществами повышения эффективности.

Изменить: Так как кажется, что вы все еще находите среди обучающих объектно-ориентированных концепций (которые намного сложнее освоить, чем любого синтаксиса языка), я высоко рекомендую сбор копии PHP-объектов, шаблонов и практики Мэтта Зандстра. Это книга, которая впервые научила меня эффективно использовать ООП, а не просто преподавать мне синтаксис. Я изучил синтаксис за несколько лет до этого, но это было бесполезно без понимания "почему" ООП.

  • 3
    Книга, рекомендованная в редакции этого поста, действительно очень хороша. Кусок, который я до сих пор оказался весьма поучительным. Первые несколько глав ответили на большинство моих вопросов, связанных с классом.
  • 0
    Дэвид А Тейлор написал книги, которые позволили мне по-настоящему понять объекты, не затрачивая на размышления ненужные подробности, например « Объектно-ориентированные технологии: руководство менеджера и бизнес-инжиниринг с использованием объектной технологии» . На обеих страницах по 100 страниц, и каждый из них достаточно прост для чтения во второй половине дня. Конечно, есть Gamma et al. Design Patterns , хотя основной подход можно просто описать как «подкласс того, что вы хотите изменить».
Показать ещё 1 комментарий
76

private - может быть доступен только из класса ININ только

protected - может быть доступен из класса WITHIN и INHERITING

public - может быть доступен из кода OUTSIDE класса также

Это относится как к функциям, так и к переменным.

  • 0
    Не уверен, что защищенное определение здесь правильно, из фактически выбранного ответа кажется, Защищенный - Доступ к нему возможен только из унаследованного класса и далее, а не из исходного / родительского класса. Сказать «В классе» может быть немного странно.
  • 7
    Я так не думаю, на самом деле кажется, что выбранный ответ - тот, который здесь сбивает с толку. Смотрите комментарий шахидов. ИМХО, защищенный метод очень хорошо доступен из исходного класса.
Показать ещё 4 комментария
25

Разница заключается в следующем:

Public:: Доступ к открытой переменной или методу может получить любой пользователь этого класса.

Protected:: Защищенная переменная или метод не могут быть доступны пользователям класса, но могут быть доступны внутри подкласса, который наследуется от класса.

Private:: Частная переменная или метод могут быть доступны только внутри класса, в котором он определен. Это означает, что личную переменную или метод нельзя вызывать из дочернего объекта, который расширяется класс.

  • 0
    Я думаю, что это должен быть принятый ответ
  • 0
    Это самый ясный ответ.
16

Области видимости с Абстрактные примеры:: Легко понять

Эта видимость свойства или метода определяется объявлением предварительной фиксации одного из трех ключевых слов (Public, protected и private)

Публичная. Если свойство или метод определены как общедоступные, это означает, что он может быть доступен и управляться любым, что может ссылаться на объект.

  • Реферат, например. Подумайте о широте видимости общественности как "публичный пикник" , к которому может прийти любой человек.

Защищено:, когда доступность свойств или методов для защищенных членов может быть доступ только внутри самого класса и унаследованных и наследующих классов. (Унаследовано: - класс может иметь все свойства и методы другого класса).

  • Подумайте, как защищенную область видимости как "Пикник компании" , где члены компании и члены их семей разрешены не публике. Это наиболее распространенное ограничение объема.

Закрыто: Когда свойство или видимость метода настроено на закрытый, только класс с частными членами может получить доступ к этим методам и свойствам (внутри внутри класса), несмотря на то, может быть.

  • с аналогией пикника считают пикником компании , где на пикнике допускаются только члены компании. а не семье, не допускается публикация широкой публики.
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

11

️ Вот простой способ запомнить область public, protected и private.

PUBLIC:

  • public область: общедоступная переменная/функция доступна как для объектов, так и для других классов.

PROTECTED:

  • protected область: защищенная переменная/функция доступна для всех классов, которые расширяют текущий класс.
  • Нет! Объекты не могут получить доступ к этой области

PRIVATE:

  • private область: Закрытая переменная/функция видна только в текущем классе, где она определяется.
  • Нет! Класс, расширяющий текущий класс, не может получить доступ к этой области.
  • Нет! Объекты не могут получить доступ к этой области.

Прочитайте видимость метода или переменной в руководстве по PHP.

8

Учитывая "когда":
Я склонен объявлять все как частное изначально, если я не совсем уверен. Причина в том, что частный метод обычно гораздо проще сделать публичным, чем наоборот. Это потому, что вы можете быть уверены, что приватный метод нигде не использовался, кроме как в самом классе. Публичный метод уже может использоваться везде, возможно, требующий обширной переписывания.

Обновление: в настоящее время я использую protected стандарт по умолчанию, потому что я обнаружил, что он достаточно хорош для инкапсуляции и не мешает расширению классов (чего я в любом случае стараюсь избегать). Только если у меня будет веская причина использовать два других, я сделаю это.

Хорошей причиной для private метода может быть тот, который реализует что-то, присущее этому объекту, что даже расширяющийся класс не должен изменяться (фактическая причина, в дополнение к инкапсуляции, как внутреннее управление состоянием). В конце концов, все еще достаточно легко отследить, где обычно используется protected метод, поэтому в настоящее время я по умолчанию использую protected. Может быть, не 100% объективный опыт "в окопах", я признаю.

  • 3
    С вашим обновлением: Можете ли вы прояснить, как «достаточно хороший» и «хороший повод» сочетаются здесь? Например, использование private было бы все еще «достаточно хорошим» для использования, но вы не предлагаете, чтобы, хотя более ранние причины, которые вы приводили, звучат как «хорошая причина»: инкапсуляция.
  • 0
    @hakre: причина, по которой мы должны стремиться к инкапсуляции, состоит в том, чтобы избежать утечки состояния во внешнюю область. protected делает это уже, но вы сохраняете его гибким для расширения / наследования. Опять же, если у вас нет веских причин сделать это private .
Показать ещё 2 комментария
6

Для меня это самый полезный способ понять три типа свойств:

Публичная. Используйте это, когда вы в порядке, когда эта переменная напрямую доступна и изменена из любого места вашего кода.

Пример использования извне класса:

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

Защищенный. Используйте это, когда вы хотите заставить других программистов (и самостоятельно) использовать getters/seters вне класса при доступе и настройке переменных (но вы должны быть последовательными и использовать геттеры и сеттеры внутри класса). Это или private имеют тенденцию быть стандартным способом, когда вы должны настроить все свойства класса.

Почему? Потому что, если вы решите в какой-то момент в будущем (может быть, даже в течение 5 минут), что вы хотите манипулировать значением, которое возвращается для этого свойства или что-то с ним делать до получения/настройки, вы можете сделать это без рефакторинга везде, где есть использовал его в своем проекте.

Пример использования извне класса:

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

Частные: private свойства очень похожи на свойства protected. Но отличительная особенность/разница заключается в том, что сделать ее private также делает ее недоступной для дочерних классов без использования родительского класса getter или setter.

В принципе, если вы используете геттеры и сеттеры для свойства (или если он используется только внутри родительского класса и он не предназначен для доступа нигде), вы также можете сделать его private, просто чтобы никто не пытался использовать его напрямую и вводить ошибки.

Пример использования внутри дочернего класса (который расширяет MyObject):

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

В руководстве по PHP есть хорошее чтение по вопросу здесь.

Видимость свойства или метода может быть определена путем префикса декларации ключевыми словами public, protected или private. К членам класса, объявленным публичными, можно получить доступ во всех странах. Доступ к элементам, объявленным защищенными, может быть доступен только внутри самого класса и наследуемых и родительских классов. Участникам, объявленным как private, может быть доступен только класс, определяющий участника.

4

Переменные в PHP отображаются в трех разных типах:

Публикация: значения этих типов переменных доступны во всей области действия и вызывают выполнение кода. объявить как: public $examTimeTable;

Закрыто: значения этого типа переменных доступны только для класса, к которому он принадлежит.  private $classRoomComputers;

Защищено: значения этого класса доступны и доступны только в том случае, если Access был предоставлен в виде наследования или их дочернего класса. обычно используется :: для предоставления доступа родительским классом

protected $familyWealth;

4

Они там, чтобы допускать разные уровни encapsulation

  • 8
    Вы, возможно, могли бы это немного прояснить.
3

Возрождение старого вопроса, но я думаю, что действительно хороший способ подумать об этом - с точки зрения API, который вы определяете.

  • public - Все, что является общедоступным, является частью API, который будет использовать и полагаться любому, кто использует ваш класс/интерфейс/другой.

  • protected - Не обманывайте себя, это тоже часть API! Люди могут подклассы, расширять ваш код и использовать что-либо помеченное как защищенное.

  • private - Частные свойства и методы могут быть изменены так, как вам нравится. Никто другой не может их использовать. Это единственные вещи, которые вы можете изменить, не внося изменений.

Или в Semver условия:

  • Изменения во что-либо public или protected должны рассматриваться как ОСНОВНЫЕ изменения.

  • Все новые public или protected должны быть (по крайней мере) MINOR

  • Только новое/изменение чего-либо private может быть PATCH

Итак, с точки зрения поддержания кода, хорошо быть осторожным в отношении того, что вы делаете public или protected, потому что это то, что вы обещаете своим пользователям.

1

Public: это состояние по умолчанию, когда вы объявляете переменную или метод, к которому можно получить доступ непосредственно к объекту.

Защищено: Доступ к нему возможен только внутри объекта и подклассов.

Частный: может ссылаться только на объект, а не на подклассы.

0

Когда мы следуем объектно-ориентированному php в нашем проекте, мы должны следовать некоторым правилам, чтобы использовать модификаторы доступа в php. Сегодня мы собираемся четко узнать, что такое модификатор доступа и как мы можем его использовать. Модификаторы доступа PHP используются для установки прав доступа с классами PHP и их членами, которые являются функциями и переменными, определенными в области видимости класса. В php есть три области для учеников.

  1. ОБЩЕСТВЕННОЕ
  2. ЧАСТНЫЙ
  3. ЗАЩИЩЕНЫ

Теперь давайте взглянем на следующее изображение, чтобы понять уровень доступа модификатора доступа Изображение 724

Теперь давайте взглянем на следующий список, чтобы узнать о возможных ключевых словах PHP, используемых в качестве модификаторов доступа.

public: - класс или его члены, определенные с помощью этого модификатора доступа, будут публично доступны из любого места, даже вне области действия класса.

private: - члены класса с этим ключевым словом будут доступны внутри самого класса. мы не можем получить доступ к частным данным из подкласса. Он защищает членов от доступа извне класса.

protected: - то же самое как private, за исключением того, что позволяет подклассам получать доступ к защищенным членам суперкласса.

Теперь посмотрите таблицу, чтобы понять модификатор доступа. Читать статью php access modifire.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню