<rmcreative>

RSS

Вызов private-метода из static-метода

15 февраля 2010

Вот таким чудом озадачили меня Фёдор (unno.ru) и mihailt.

class A {
  private function action(){
    echo 1;
  }
  public static function callAction(A $a){
    $a->action();
  }
}
 
$a = new A;
A::callAction($a);
  1. Это работает.

  2. Я сомневаюсь, что могу на 100% верно объяснить, почему оно работает.

Если вы сможете — обязательно напишите в комментариях.

update

Контекст модификаторов — класс, а не объект! И верно это для всех популярных реализаций ООП (на всякий случай проверили АS3 и Java).

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

  1. №2257
    vasa_c
    vasa_c 15.02.2010, 17:45:45

    Вызываем приватный метод из другого метода того же класса. Что страшного тут?

    Тот же синглтон - вызов скрытого конструктора из статического метода.

    Аналогично и из нестатического метода можно вызвать приватный другого объекта того же класса.

  2. №2258
    Zadoev Roman
    Zadoev Roman 15.02.2010, 17:47:20

    someAction статический метод, который получает внутри в перменную $self экземпляр класса через getInstance() реализующий singleton.

    Фикус этого метода в new self, что в конкретной этой строке эквивалентно new A(), причем вызывается это внутри класса, поэтому protected __constructor отрабатывает.

    Далее фикус в том что getInstance в явном виде не записывает экземпляр класса в A::$instance, это делается внутри __constructor() в рамках выполнения которого указатель на текущий объект уже доступен.

    Ну далее getIntance возвращает ссылку на созданный экземпляр класса, у коотрого уже дергается нужный метод.

  3. №2259
    Zadoev Roman
    Zadoev Roman 15.02.2010, 17:48:49

    Пока писал пример поменялся. :) Тут вообще все тривиально.

  4. №2261
    mihailt
    mihailt 15.02.2010, 17:56:20

    **Zadoev Roman **

    тривиально, то тривиально, но вроде так недолжно быть так как не смотря на то что переменная $a экземпляр класса А,

    метод action - это метод объекта, следовательно должен быть доступен только внутри объекта $a через ключевое слово $this

  5. №2262
    Sam
    Sam 15.02.2010, 18:07:48

    Zadoev Roman

    За изменённый код извиняюсь — нашёлся пример попроще.

    У меня похожее объяснение, но, подозреваю, что в чём-то оно некорректно.

  6. №2263
    unno
    unno 15.02.2010, 18:16:15

    Members declared as private may only be accessed by the class that defines the member.

    Во как дело-то обстоит оказывается. В PHP в этом случае мы имеем дело не с object scope, а class scope, потому так и получается. Не понятно, правда, почему.

  7. №2264
    Mike TUMS
    Mike TUMS 15.02.2010, 18:25:09

    Начали спорить с программером. Он до сих пор не понимает что A::callAction() != $a->callAction(), и поэтому для него тут всё нормально (либо он ламер криворукий, либо я дурак).

    Лично я бы писал баг-репорт.

  8. №2265
    mihailt
    mihailt 15.02.2010, 18:28:32

    собственно RTFM ))

  9. №2266
    Ewg
    Ewg 15.02.2010, 18:29:03

    Где здесь чудо? Что здесь удивительного?

  10. №2267
    Mike TUMS
    Mike TUMS 15.02.2010, 18:33:13

    mihailt так кто прав-то?) я просто сам чайник)

  11. №2268
    Артём Курапов
    Артём Курапов 15.02.2010, 18:34:45

    Не вижу никаких проблем. Статичный метод в котором работает ранее созданный объект.

    То же самое с тем что по rss было. Просто там через singleton делалось.

    В заблуждение может ввести начинающих программеров :P

  12. №2269
    Sam
    Sam 15.02.2010, 18:35:33

    Удивительно то, что была некая доля уверенности, что модификаторы работают в контексте объекта, а не класса. И, как я понял, не только у меня.

  13. №2271
    Sam
    Sam 15.02.2010, 18:40:00

    Артём Курапов

    В заблуждение, может ввести любого, кто с этим не сталкивался и давно читал мануалы. У меня опыт с Java / PHP довольно неплохой, но «понадобилось» такое в первый раз :)

  14. №2272
    mihailt
    mihailt 15.02.2010, 18:40:36

    собственно да, я тоже так думал

  15. №2273
    Zadoev Roman
    Zadoev Roman 15.02.2010, 18:49:12

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

    Но больше меня повеселил вот такой код.

    <?php
     
    error_reporting(E_ALL);
    ini_set('display_errors', 'on');
     
    class A
    {
     
     public function getName()
     {
      echo 'A';
     }
     
     public function getClassName()
     {
      $this->getName();
     }
    }
     
     
    class B
    {
     public function getName()
     {
      echo 'B';
     }
     
     public function getClassName()
     {
      A::getClassName();
     }
     
    }
     
    $b = new B();
    $b->getClassName();
  16. №2274
    Vladimir
    Vladimir 15.02.2010, 18:59:54

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

  17. №2275
    Steward
    Steward 15.02.2010, 19:08:35

    Прочитав топик и все комментарии так и не догнал в чём прикол... какие-то разногласия по поводу класса и объекта... кого-то веселят такие примеры.... ничего не понял....

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

    люди!!!! просветите в чём прикол!!!! а то мужики-то и не знают!!!

    нет я серьёзно... не дайте умереть идиотом!

  18. №2276
    Steward
    Steward 15.02.2010, 19:10:32

    При таком объявлении

    class A {

    private function action(){

    echo 1;
    
    

    }

    public static function callAction(A $a){

    $a->action();
    
    

    }

    }

    сработает даже (должно сработать!)

    $a = new A;

    A::action();

  19. №2277
    Steward
    Steward 15.02.2010, 19:11:58

    а не гоню... приватные методы и свойства видны только для самого класса... - потрите нафиг предыдущий коммент :))

  20. №2280
    Sam
    Sam 15.02.2010, 20:35:41

    Steward

    Прикол в том, что в книгах и на лекциях это даётся быстро и внимание на этом не заостряется. Студенты вообще разницу между классом и объектом не понимают. А когда начинают понимать, основы уже не перечитывают. Ну а так как на практике такое встречается крайне редко, за пяток лет такие штуки забываются. Я, например, забыл. Как, впрочем, и многие другие.

  21. №2281
    Sam
    Sam 15.02.2010, 20:39:51

    Zadoev Roman

    Тоже занятный случай.

  22. №2282
    Steward
    Steward 15.02.2010, 20:54:47

    Sam... а если не так, то как ещё можно использовать приватные методы?!... где их вообще тогда вызывать?

    чего-то вы не то сказали...

    я институт закончил 10 лет назад, лекции по ООП была 14 лет назад... как ни странно но именно это я чётко помню до сих пор..

  23. №2283
    Sam
    Sam 15.02.2010, 22:56:06

    Как где вызывать? В том же самом объекте, в котором этот самый метод определён. Это наиболее частое использование. А вот вызов из другого объекта того же класса — это уже не очень стандартный вариант.

  24. №2284
    Евгений Злобин
    Евгений Злобин 16.02.2010, 7:52:15

    Граждане, почитайте в вики и всё станет ясно, что это, зачем и почему. http://ru.wikipedia.org/wiki/Singleton

  25. №2285
    msi
    msi 16.02.2010, 11:08:55

    Ребята, о чем вы пишете, что вы подразумеваете под модификаторами класса и объекта?!

    Объект - это экземпляр класса.

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

    Модификаторы доступа могут быть только у класса! Объект - это то что построено на основании класса, у него нету модификаторов!

    Если взять пример со строительством/архитектурой, то класс - это чертеж дома, а дом - это уже объект.

    Когда вы правильно разделите эти понятия, тогда и не будет возникать таких вопросов, тут все логично и правильно, будет работать такая конструкция во всех языках программирования поддерживающих ООП. Навскидку, написал этот пример на C#, Java, Delphi и C++ - везде работает, чего и следовало ожидать.

    Прочитайте определение класса и объекта хотя бы на той же википедии.

  26. №2286
    vasa_c
    vasa_c 16.02.2010, 11:57:30

    msi, с абстрактно-теоретической точки зрения не совсем логично и правильно. Например, система водопровода в доме это внутренняя реализация, до которой должно быть дело только этому дому. А лезть при реализации водопровода в одном доме, в водопровод другого не совсем правильно, даже если дома идентичны.

    Так же по-правильному в приватную область объекта не должен лезть никто, даже точно такой же объект.

  27. №2287
    Mike TUMS
    Mike TUMS 16.02.2010, 12:09:34

    Согласен с vasa_c. Именно так думал и я при рассмотрении этой задачки.

    @msi, что значит "Модификаторы доступа могут быть только у класса! Объект - это то что построено на основании класса, у него нету модификаторов!"? имхо бред.

  28. №2288
    msi
    msi 16.02.2010, 12:18:44

    @vasa_c согласен с вами, что это не совсем корректно - это называется антипаттерн проектирования Паблик Морозов, то есть открытие приватного члена класса через другой метод этого класса, со стороны архитектуры - это неверно, но со стороны конструкций ООП вполне возможно.

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

    @Mike TUMS да нет, это не бред, класс описывает структуру. У него и есть модификаторы доступа, то есть он описывает, может ли быть вызван данный метод из другого объекта. А объект - это то что построено на основании этого класса, то есть он использует структуру класса, в которой описаны методы. Модификаторы доступа - это описание способа доступа, а не поведение готового объекта. В этом и разница между классом (шаблоном) и объектом (реализацией этого шаблона).

  29. №2289
    Makc
    Makc 16.02.2010, 12:36:22

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

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

    С другой стороны, не такая уж и неожиданная особенность, поэтому соглашусь с @msi: модификаторы доступа ставятся на доступность метода/поля из класса, а не из конкретного объекта, хотя обычно ожидаешь их именно на объекте.

  30. №2290
    Mike TUMS
    Mike TUMS 16.02.2010, 12:44:36
    &lt;?php
    class A {
      private $foo = "barn";
     
      private function show() {
        echo $this->foo;
      }
     
      public function get($object) {
        $object->show();
      }
    }
     
    $a = new A;
    $b = new A;
     
    $b->get($a);

    Я извиняюсь, но это пиздец. На кой хрен тогда вообще нужны модификаторы?

  31. №2291
    Mike TUMS
    Mike TUMS 16.02.2010, 12:55:58

    даже не так.

    class A {
      private $foo = "bar";
      private $objectname = '';
     
      public function __construct($name) {
        $this->objectname = $name;
      }
     
      private function show() {
        echo $this->foo;
        echo $this->objectname;
      }
     
      public function get($object) {
        $object->show();
      }
    }
     
    $a = new A('a');
    $b = new A('b');
     
    $b->get($a);
  32. №2292
    msi
    msi 16.02.2010, 13:22:26

    @Mike TUMS вы постоянно приводите реализацию антипаттерна Паблик Морозов. С точки зрения архитектуры - это некорректно. С точки зрения конструкция ООП - все верно.

    public class A
    {
      private string _name;
     
      public A()
      {
        _name = "MyName";
      }
     
      public string Name
      {
        get { return _name; }
      }
    }

    такая конструкция надеюсь вас не смущает? С точки зрения конструкций языка это то же самое, что приводите вы, и с точки зрения архитектуры - все тоже правильно.

    При создании объекта вы не увидите в нем свойства _name (потому что оно скрыто модификатором класса), но доступ к полю Name (потому что оно открыто модификатором класса) у вас будет в экземпляре класса, хотя фактически он покажет наружу то же поле _name. Это и есть один из основных принципов ООП - инкапсуляция.

  33. №2293
    Makc
    Makc 16.02.2010, 13:22:39

    Mike TUMS, а в чем вообще проблема? Вызвали show() у $a, а хотим, чтобы отработало для $b или вообще отказалась отрабатывать? Тогда некоторые шаблоны проектирования перестанут работать, отвалится методы клонирования и т.д.

  34. №2295
    Mike TUMS
    Mike TUMS 16.02.2010, 14:14:56

    @msi про инкапсуляцию, и в частности реализацию __set()/__get(), я в курсе. Про Паблик Морозова не знал =)

    @Makc если честно - ожидал Fatal error: Call to private method A::show().

  35. №2297
    White Shadow
    White Shadow 16.02.2010, 23:54:11

    Ну, а почему должен быть error?

    1. Реализация класса позволяет такое делать, значит нужно, это же для произвольного класса не работает.

    можно вообще вот так сделать:

    public function get($object, $action) {
        $object->$action();
    }
    1. По смыслу происходящего проверка осуществляется простая:

    если имя класса объекта вызывающего метод == имени класса объекта в котором этот метод объявлен, то можно вызывать и private методы (если это тот же класс, то мы знаем что делать с ними и ничего не "попортим")

    но это может всплыть много где, где есть реализация магических методов __get/__set/__call например ORM'ы и т.п., поэтому существует практика начинать названия private и protected свойств, методов с подчеркивания (_name), тогда фильтровать обращения к ним - тривиальная задача (и autocomplete сразу видно что public, а что нет)

  36. №3425
    Владимир
    Владимир 20.11.2010, 17:48:16

    Прочитал первые посты и проблевался, вот такой баг, бля, надо чтобы был потому что это Singleton такой, закончили институт 10 лет назад, лол. Это все баги и не доработки, синглтон? Просто надо сделать private конструктор, а получить new с помощью getInstance() и проверить статический счетчик, мудилы, а лезть внутрь private метода, никто не разрешает, ну это исправлят.

  37. №3426
    Владимир
    Владимир 20.11.2010, 17:57:54

    И вообще создать объект одна операция, а созданный трогать - другая.

  38. №4104
    php programming
    php programming 13.03.2011, 23:36:21

    А как объяснить вот это:

    class Foo {
        private $bar = "baz";
     
        public function getBar() {
            return $this->bar;
        }
    }
     
    class Bar extends Foo {}
     
    $o = new Bar;
    echo $o->getBar(); //baz
  39. №4105
    waone
    waone 14.03.2011, 16:13:32

    ТОЛСТО

  1. Почта опубликована не будет.

  2. Можно использовать синтаксис Markdown или HTML.

  3. Введите ответ в поле. Щёлкните, чтобы получить другую задачу.