В чем разница между публичным, частным и защищенным? - PullRequest
922 голосов
/ 06 декабря 2010

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

Примеры:

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

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

// Protected
protected $variable;
protected function doSomething() {
  // ...
}

Ответы [ 16 ]

1200 голосов
/ 06 декабря 2010

Вы используете:

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

  • private область, если вы хотите, чтобы ваше свойство / метод было видимым только в своем собственном классе.

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

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

1125 голосов
/ 20 февраля 2014

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, эти методы и свойства могут быть доступны с помощью

  • Тот же класс, который объявил это.
  • Классы, которые наследуют объявленный выше класс.

Члены посторонних не могут получить доступ к этим переменным. «Аутсайдеры» в том смысле, что они не являются экземплярами объекта самого объявленного класса.

Пример:

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

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


Рассечение класса дедушки с использованием Отражение

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

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

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

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

Преамбула

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

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

Давайте сделаем их (назначим модификаторы) public, protected и private соответственно. Вы очень хорошо знаете, что члены 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>";
}

Выход:

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


Дополнительные ресурсы:


82 голосов
/ 04 сентября 2012

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

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

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

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

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

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

76 голосов
/ 06 декабря 2010

private - можно получить доступ только из класса

protected - можно получить доступ из класса ВНУТРЕННЕГО класса и класса

public - можно получить доступ и из кода вне класса

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

25 голосов
/ 03 сентября 2012

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

Public :: Открытая переменная или метод могут быть доступны напрямую любому пользователю класса.

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

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

17 голосов
/ 07 февраля 2014

Области видимости с Абстрактные примеры :: Упрощает понимание

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

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

  • Аннотация, например. Подумайте о публичной видимости как о «публичном пикнике» , к которому может прийти каждый.

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

  • Думайте как защищенная область видимости как «Пикник компании» , где членам компании и членам их семей разрешено не публично. Это наиболее распространенное ограничение области действия.

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

  • с аналогией с пикником - «пикник компании, в который допускаются только члены компании» на пикнике. не семья и широкая публика не допускаются.
14 голосов
/ 03 октября 2013
/**
 * 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 голосов
/ 30 июня 2016

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

PUBLIC:

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

PROTECTED:

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

PRIVATE:

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

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

8 голосов
/ 28 мая 2012

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

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

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

6 голосов
/ 25 января 2016

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

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

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

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

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

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

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

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

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

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

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

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