Методы доступа. Наиболее популярные ситуации

    Статья в первую очередь расчитана на начинающих разработчиков, либо для тех, кто только начинает переходить от процедурного стиля программирования к ООП, посему матерых гуру просьба не вгонять в минуса :)

    Права доступа к свойствам и методам — это на первый взгляд всего лишь три слова: private, protected и public. Но что скрывается за ними? Какие преимущества это дает в разработке? И как их правильно использовать? Здесь, как и во всех других аспектах программирования, без практики не разобраться…

    Одна из трех основных концепций ООП — наследование (другие две: инкапсуляция и полиморфизм). Вобщем-то именно для нее и были реализованы права доступов. Основанная идея наследования: Дочерний объект, при наследовании (extend) родителя перенимает себе все родительские методы и свойства, а так же может обзавестись своими собственными. Понимая эту базу, можно перейти в всему что находится ниже…

    Private — объявляет метод или свойство доступным только в том классе в котором он присутствует. Тоесть к private методам и свойствам мы не можем обращаться ни из объектов, ни из дочерних классов.

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

    Public — публичный. Классы и методы, объявленные public, могут быть доступны как внутри самого класса, так и в дочерних классах и в объектах, реализовавших класс.

    Сразу хочу заметить, что при наследовании, методы доступа изменяться могут только к более лояльным. тоесть в следующей последовательности, но не обратно: private → protected → public

    Так же методы могут быть final тоесть такими, которые невозможно переопределить в классах потомках.

    Вобщем-то все методы доступа используются исключительно для самодокументации кода и не несут никакой логической составляющей, так что и без них жизнь только тяжела, но не невозможна, что доказывает РНР4, в котором все методы и свойства были публичными…

    Практика


    Иногда случаются ситуации, когда этих методов доступа недостаточно. Тоесть, например, мы можем хотеть иметь доступ из объекта на чтение какого-то свойства, но при этом не иметь возможности в него писать. Самое простое решение: объявить свойство public и добавить комментарий /* только для чтения */, но про комментарий можно ненароком забыть и испортить логику поведения программы, вклинившись с нестандартным значением посреди выполнения. тогда приходит время использовать геттеры (getter\'s). Геттер — не что иное, как метод класса, реализующий исключительную возможность читать не публичные свойства из объекта. Вот пример:
    class A {
        private $a = 7;//мы не можем читать и писать в это свойство из объекта, реализующего этот класс

        public function getA() { //публичный метод будет доступен объекту для обращения
            return $this->a; //внутри класса мы можем получать доступ к приватным свойствам
        }
    }

    $obj = new A();
    echo $obj->getA();//мы получили значение приватной переменной $a


    Похожим способом ведут себя и сеттеры (setter\'s), когда нам необходимо иметь возможность установить значение переменной, но не читать ее напрямую, так как она, к примеру, должна быть преобразована прежде чем быть использованной. Пример метода сеттера:
    //...
    public funtion setA($value) { //метод будет доступен для объекта
        $this->a = $value; //приватное свойство $a может быть установленное внутри класса, но не доступно для прямого влияния из объекта
    }
    //...


    Еще одним вариантом реализации доступа к методам, когда метод должен быть отовсюду доступен только для чтения, является введение \«псевдо-свойства\»:

    class A {
        public function getValue() {
            static $value;

            if (empty($value)) {
                $value = //... тут значение создается по каким-то известным параметрам и повлиять извне на него мы никак не сможем
            }

            return $value;
        }
    }

    в примере выше, класс А будет обладать псевдо-свойством $value. Псевдо — потому что оно реализуется исключительно через метод, а доступ к нему возможен только на чтение. Еще можете заметить что я использовал паттерн \«ленивой инициализации\», что бы отложить создание свойства до последнего момента и заодно как бы \«закешировать\» его. Где это можно применить, хорошо проиллюстрировано в соседнем топике об ООП в РНР.

    Хорошей практикой является сокрытие всех свойств методом private и, в зависимости от нужд, создавать для них сеттеры или геттеры, но нужно быть внимательным, что если для свойства существует и сеттер и геттер, а дополнительной логики обработки данных нет, то не проще ли их убрать, а свойство сделать публичным? :)
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 51

      +3
      Вот еще lazy-getter для сомневающихся :)

      protected function __call( $method, $value ) {
      if ( preg_match( '/^get(.+)$/', $method, $matches ) ) {
      $accessor = strtolower( substr($matches[1], 0, 1) ) . substr($matches[1], 1);

      if ( isset($this->{$accessor}) ) {
      return $this->{$accessor};
      } else {
      return false;
      }
      }
      }
        0
        Ах-ха-хах! )))
          0
          Только к этому по-идее надо карту доменного объекта накатать, ага. Н на практике преобразователь строк setPostId в post_id может понадобиться, коль уж с БД работать нужно.
            0
            > $accessor = strtolower( substr($matches[1], 0, 1) ) . substr($matches[1], 1);
            ай яй яй ))
              0
              ну я ведь тоже lazy :)
            0
            >> Вобщем-то все методы доступа используются исключительно для самодокументации кода и не несут никакой логической составляющей

            Это открытие в ООП.
              –1
              конкретный пример реализованной логики указанием метода доступа можно? :)

              "играясь" методами доступа мы лишь говорим как сделать можно, а как нельзя, или лучше не делать. Если Вы считаете это "логикой приложения", тогда да - приношу извинения…
                +2
                Да, контракты я считаю логикой создания архитектуры приложения. Самодокументируемость тут ни при чём.
                  +1
                  Публичные методы обязаны сохранять инварианты объекта, приватные - нет. Это важное отличие.

                  Хотя на практике разделение private/protected/public грубое и неудобное. В Java есть ещё один тип доступа (без указания ключевых слов), в C++ - friends. Но всё это - компенсация того факта, что на самом деле методы вообще не должны бы быть связаны с объектами.
                    0
                    > на самом деле методы вообще не должны бы быть связаны с объектами.

                    для чего нужны методы?
                    0
                    AlexeyTokar "конкретный пример реализованной логики указанием метода доступа можно? :)"
                    Можно, смотрите Singleton
                      0
                      Хе. Не, это же самодокументирование! Ну не надо создавать этот объект, или лучше не создавать!

                      ...Такое ощущение, что нас быстро научат хорошему. Записываемся в очередь.
                        0
                        Да уж. В соседней ветке меня уже просвятили, что сессия, оказывается, хранится ТОЛЬКО на стороне сервера и поэтому у пользователя нет никакого доступа к данным, сохраненным в ней.
                        То ли еще будет?
                          +1
                          То есть? К идентификатору сессии? Или к её содержимому? Как это выглядело в контексте? Может статься, что Ваш собеседник и прав в чём-то.
                            0
                            А как обстоит ситуация на самом деле?
                              0
                              При некоторых условиях можно получить данные, хранящиеся в сессии, т.к. она хранится в директории, открытой на чтение-запись с правами веб-сервера, поэтому, если пользователь сможет разместить на этом сервере свой скрипт, то он прочитает все данные, хранящиеся в сессиях пользователей этого веб-сервера.
                              Но в принципе, я тогда был не прав в некоторых аспектах.
                                0
                                А. Это ладно. А то я было подумал, что данные сессии могут храниться на стороне клиента.

                                (То есть они, конечно, могут, если хэндлер соответствующий написать и в cookie их хранить, к примеру, но это если только специально устроить.)
                    0
                    1. правильно extends

                    2. стоить связать инкапсуляцию и getter/setter по смыслу
                      0
                      1. тогда уж "Inheritance"

                      2. стоит, но не для этой статьи. а для материалов по теории ООП
                      0
                      >Protected — объявляет метод или свойство защищенными. Тоесть такими, которые не могут быть доступны из объекта, реализующего класс, но вполне может быть использовано в дочерних классах.
                      Это как?
                        0
                        ндя.. неудачно выразился... имелись ввиду методы класса-родителя.. ну вы то поняли :)
                          0
                          Не, не поняли.
                          0
                          т.е. наследник внутри себя может оперировать этими свойствами, но когда вы попытаетесь инстанцировать объект наследника и обратиться к свойству через указатель, то ничего у вас не выйдет.
                          class someClass
                          {
                          protected $someVal;
                          }

                          class someClassElse extends someClass
                          {
                          function someFunc()
                          {
                          //здесь можно обратиться к $this->someVal
                          }
                          }

                          $obj = new someClass;
                          $obj->someVal = 'что-нить'; //А вот тут - никак.

                          $objelse = new someClassElse;
                          $objelse->someVal = 'что-нить'; //А вот тут - тоже никак, пока в someClassElse не переопределите свойство с методом public.
                            0
                            тьфу. "с методом" зачеркнуть ) Спать пора.
                              0
                              я бы сказал следующий пример более нагляден:

                              class A {
                              protected $a;
                              }

                              class B extends A {
                              public function b() {
                              echo $this->a;
                              }
                              }

                              $a = new A();
                              $a->a; //не можем обратиться

                              $b = new B();
                              $b->b(); // вернет значение свойства $a класса A
                                0
                                null он вернёт.
                                  0
                                  eгу. потому что pyfчение свойства $a в данный момент = null
                                    0
                                    прошу прощения:
                                    *значение
                                      0
                                      Не только. Потому что echo ничего не возвращает.
                                        0
                                        :-D
                                        да. чисто машинально отписал :) но, имхо, Вы придираетесь
                                          0
                                          Имхо, нет. Потому как люди, которые знают, для чего нужны спецификаторы, и так знают, и никаким самодокументированием их с панталыку не сбить. А люди, которые не знают, могут быть введены в заблуждение.
                                          Ну и получается, что цели у Вас могло быть минимум три:
                                          1) научить всех, что такое спецификаторы доступа;
                                          2) написать своё мнение, что это такое, чтобы Вам пообъясняли;
                                          3) показать, что Вы знаете, что это такое.

                                          :-)))

                                          В первом случае любая придирка поможет новичкам, во втором — Вам лично, в третьем, пожалуй, тоже.
                                            0
                                            а Вы во всем ищите скрытый подтекст? ;)

                                            возможно иногда стоит читать и воспринимать материал именно так как он написан, а не пытаться вникнуть между строк? ;)
                                              0
                                              http://alexeytokar.habrahabr.ru/blog/372…

                                              Сами себе противоречите.
                                                0
                                                нисколько. то что некорректно объяснил, еще не значит что просил читать между строк...
                                                  0
                                                  Да Вы много что объяснили некорректно. Но дальше следует странное: в некоторых случаях "ну вы же поняли", в некоторых "а я вас не просил понимать". Прочёл как написано — придираюсь. Попробовал понять, в чём цель поста и его последствий — меня не просили читать между строк.
                              0
                              Есть еще такая штука, что доступ к защищенным методам и свойствам объекта возможен из static-методов того же класса (если идет обращение к private-свойствам), или классов-наследников и классов-родителей (если идет обращение к protected-свойствам).

                              Иными словами, следующий код корректен:

                              class A
                              {
                              private $a = 'protected var';
                              private function __construct()
                              {}

                              public static function outputA()
                              {
                              $obj = new A();
                              echo $obj->a;
                              }
                              }

                              A::outputA(); // выведет 'protected var'
                                0
                                Ну а почему ему не быть корректным? метод то public, только определение static добавили
                                  0
                                  Это не настолько очевидно, как может показаться с первого взгляда )) Мы ведь обращаемся к закрытому свойству объекта $obj (как бы извне).
                                    0
                                    обращаемся к публичному методу :) тут уже всё на совести разработчика, к чему давать к чему не давать )
                                      0
                                      по-моему Вы не уловили суть создание экземпляра класса :)
                                      хотя я и не уверен что код корректен, но если это так - спасибо за новое открытие для меня :)
                                        0
                                        да, каюсь, невнимательно просмотрел код. Но имхо это больше походит на чудеса ООП php, чем на стандарты ООП :)
                                          +1
                                          Да все ОК, нормальный ООП. Почему же метод не должен иметь доступ к скрытым полям класса? :) Ну и что, что он статический...
                                            0
                                            я тоже так сначала подумал, но потом присмотрелся вот на эту конструкцию:
                                            $obj = new A();
                                            echo $obj->a;
                                            в статическом методе, т.е. она почему то аналогична строчке: echo $this->a; но $this в статике использовать нельзя :)
                                            В любом другом месте вызов
                                            $obj = new A();
                                            echo $obj->a;
                                            не прокатит
                                              0
                                              Я заметил это, да. Действительно, чисто внешне код выглядит странно. Но если подумать, то все получается вполне логично :) Другое дело, что ситуация какая-то весьма искусственная.
                                                0
                                                Так доступ-то ограничивается не объектом, а классом. В данном случае за пределы класса мы не выходим, поэтому и видим защищённые переменные.
                                              0
                                              Нет, это не чудеса PHP )) В Java точно такая же ситуация.
                                    0
                                    Еще для доступа к свойствам возможен такой прием:
                                    class A {
                                    private $var1='1';
                                    protected $var2='2';
                                    public $var3='3';

                                    public function __get($name) {
                                    $prop=new ReflectionProperty(__CLASS__,$name);
                                    if ($prop->isPublic()) {
                                    return $this->$name;
                                    }
                                    }
                                    }

                                    $obj=new A;
                                    var_dump($obj->var3);
                                    Т.е. исскуствено ограничиваем доступ к защищенным свойствам через __get()
                                      0
                                      Только осваиваю ООП.. Не понял зачем делать свойства private. Не могли бы Вы привести пример, где это может быть полезно?
                                        0
                                        где угодно, когда состояние нужно сохранить, но не допускать прямого вмешательства извне объекта... примеров множество можно найти в любом ООП коде :)
                                          0
                                          То есть это больше защита от дурака? :)
                                            0
                                            вобщем-то да :) перечитайте вот эту ветку каментов - тут ан эту тему даже холивар начался :)

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                      Самое читаемое