Вызов 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);
Это работает.
Я сомневаюсь, что могу на 100% верно объяснить, почему оно работает.
Если вы сможете — обязательно напишите в комментариях.
update
Контекст модификаторов — класс, а не объект! И верно это для всех популярных реализаций ООП (на всякий случай проверили АS3 и Java).
Комментарии RSS по email OK
Вызываем приватный метод из другого метода того же класса. Что страшного тут?
Тот же синглтон - вызов скрытого конструктора из статического метода.
Аналогично и из нестатического метода можно вызвать приватный другого объекта того же класса.
someAction статический метод, который получает внутри в перменную $self экземпляр класса через getInstance() реализующий singleton.
Фикус этого метода в new self, что в конкретной этой строке эквивалентно new A(), причем вызывается это внутри класса, поэтому protected __constructor отрабатывает.
Далее фикус в том что getInstance в явном виде не записывает экземпляр класса в A::$instance, это делается внутри __constructor() в рамках выполнения которого указатель на текущий объект уже доступен.
Ну далее getIntance возвращает ссылку на созданный экземпляр класса, у коотрого уже дергается нужный метод.
Пока писал пример поменялся. :) Тут вообще все тривиально.
**Zadoev Roman **
тривиально, то тривиально, но вроде так недолжно быть так как не смотря на то что переменная $a экземпляр класса А,
метод action - это метод объекта, следовательно должен быть доступен только внутри объекта $a через ключевое слово $this
Zadoev Roman
За изменённый код извиняюсь — нашёлся пример попроще.
У меня похожее объяснение, но, подозреваю, что в чём-то оно некорректно.
Members declared as private may only be accessed by the class that defines the member.
Во как дело-то обстоит оказывается. В PHP в этом случае мы имеем дело не с object scope, а class scope, потому так и получается. Не понятно, правда, почему.
Начали спорить с программером. Он до сих пор не понимает что A::callAction() != $a->callAction(), и поэтому для него тут всё нормально (либо он ламер криворукий, либо я дурак).
Лично я бы писал баг-репорт.
собственно RTFM ))
Где здесь чудо? Что здесь удивительного?
mihailt так кто прав-то?) я просто сам чайник)
Не вижу никаких проблем. Статичный метод в котором работает ранее созданный объект.
То же самое с тем что по rss было. Просто там через singleton делалось.
В заблуждение может ввести начинающих программеров :P
Удивительно то, что была некая доля уверенности, что модификаторы работают в контексте объекта, а не класса. И, как я понял, не только у меня.
Артём Курапов
В заблуждение, может ввести любого, кто с этим не сталкивался и давно читал мануалы. У меня опыт с Java / PHP довольно неплохой, но «понадобилось» такое в первый раз :)
собственно да, я тоже так думал
Вообще поведение неприятное, я видел двух людей которым эти грабли сильно жизнь повеселили.
Но больше меня повеселил вот такой код.
Вообще-то не должно работать. Получается, что любой private-метод можно так вызывать. Пропадает смысл private. С другой стороны, если это пофиксить, то перестанет работать шаблон Singleton, уже упомянутый здесь.
Прочитав топик и все комментарии так и не догнал в чём прикол... какие-то разногласия по поводу класса и объекта... кого-то веселят такие примеры.... ничего не понял....
может я чего-то не понимаю, но о том что экземпляр класса (в некоторых книгах - объект класса) имеет доступ к собственным приватным методам и приватным свойствам, объявленным в классе (в некоторых книгах - декларации или объявлении класса или объекта(!!!)) говорится чуть ли не на первой лекции в институте и в первой же главе любой книги по ООП...
люди!!!! просветите в чём прикол!!!! а то мужики-то и не знают!!!
нет я серьёзно... не дайте умереть идиотом!
При таком объявлении
class A {
private function action(){
}
public static function callAction(A $a){
}
}
сработает даже (должно сработать!)
$a = new A;
A::action();
а не гоню... приватные методы и свойства видны только для самого класса... - потрите нафиг предыдущий коммент :))
Steward
Прикол в том, что в книгах и на лекциях это даётся быстро и внимание на этом не заостряется. Студенты вообще разницу между классом и объектом не понимают. А когда начинают понимать, основы уже не перечитывают. Ну а так как на практике такое встречается крайне редко, за пяток лет такие штуки забываются. Я, например, забыл. Как, впрочем, и многие другие.
Zadoev Roman
Тоже занятный случай.
Sam... а если не так, то как ещё можно использовать приватные методы?!... где их вообще тогда вызывать?
чего-то вы не то сказали...
я институт закончил 10 лет назад, лекции по ООП была 14 лет назад... как ни странно но именно это я чётко помню до сих пор..
Как где вызывать? В том же самом объекте, в котором этот самый метод определён. Это наиболее частое использование. А вот вызов из другого объекта того же класса — это уже не очень стандартный вариант.
Граждане, почитайте в вики и всё станет ясно, что это, зачем и почему. http://ru.wikipedia.org/wiki/Singleton
Ребята, о чем вы пишете, что вы подразумеваете под модификаторами класса и объекта?!
Объект - это экземпляр класса.
Класс - это тип данных описывающий какую-то заранее заданную структуру данных, с возможностью модификации внутреннего состояния при помощи методов.
Модификаторы доступа могут быть только у класса! Объект - это то что построено на основании класса, у него нету модификаторов!
Если взять пример со строительством/архитектурой, то класс - это чертеж дома, а дом - это уже объект.
Когда вы правильно разделите эти понятия, тогда и не будет возникать таких вопросов, тут все логично и правильно, будет работать такая конструкция во всех языках программирования поддерживающих ООП. Навскидку, написал этот пример на C#, Java, Delphi и C++ - везде работает, чего и следовало ожидать.
Прочитайте определение класса и объекта хотя бы на той же википедии.
msi, с абстрактно-теоретической точки зрения не совсем логично и правильно. Например, система водопровода в доме это внутренняя реализация, до которой должно быть дело только этому дому. А лезть при реализации водопровода в одном доме, в водопровод другого не совсем правильно, даже если дома идентичны.
Так же по-правильному в приватную область объекта не должен лезть никто, даже точно такой же объект.
Согласен с vasa_c. Именно так думал и я при рассмотрении этой задачки.
@msi, что значит "Модификаторы доступа могут быть только у класса! Объект - это то что построено на основании класса, у него нету модификаторов!"? имхо бред.
@vasa_c согласен с вами, что это не совсем корректно - это называется антипаттерн проектирования Паблик Морозов, то есть открытие приватного члена класса через другой метод этого класса, со стороны архитектуры - это неверно, но со стороны конструкций ООП вполне возможно.
Вы же можете, к примеру открыть доступ на чтение к приватному полю класса, которое будет изменяться только внутренней логикой самого класса, а наружу отдавать результат.
@Mike TUMS да нет, это не бред, класс описывает структуру. У него и есть модификаторы доступа, то есть он описывает, может ли быть вызван данный метод из другого объекта. А объект - это то что построено на основании этого класса, то есть он использует структуру класса, в которой описаны методы. Модификаторы доступа - это описание способа доступа, а не поведение готового объекта. В этом и разница между классом (шаблоном) и объектом (реализацией этого шаблона).
Думаю, в начале это был баг (или фича), связанная с несовершенством компиляторов: вызовы методов, их права проверялись при компиляции, а во время выполнения можно вызвать что угодно откуда угодно.
А потом уже на данной особенности стали уже и ориентироваться при разработке (тем более, что иногда она бывает очень полезна).
С другой стороны, не такая уж и неожиданная особенность, поэтому соглашусь с @msi: модификаторы доступа ставятся на доступность метода/поля из класса, а не из конкретного объекта, хотя обычно ожидаешь их именно на объекте.
Я извиняюсь, но это пиздец. На кой хрен тогда вообще нужны модификаторы?
даже не так.
@Mike TUMS вы постоянно приводите реализацию антипаттерна Паблик Морозов. С точки зрения архитектуры - это некорректно. С точки зрения конструкция ООП - все верно.
такая конструкция надеюсь вас не смущает? С точки зрения конструкций языка это то же самое, что приводите вы, и с точки зрения архитектуры - все тоже правильно.
При создании объекта вы не увидите в нем свойства _name (потому что оно скрыто модификатором класса), но доступ к полю Name (потому что оно открыто модификатором класса) у вас будет в экземпляре класса, хотя фактически он покажет наружу то же поле _name. Это и есть один из основных принципов ООП - инкапсуляция.
Mike TUMS, а в чем вообще проблема? Вызвали show() у $a, а хотим, чтобы отработало для $b или вообще отказалась отрабатывать? Тогда некоторые шаблоны проектирования перестанут работать, отвалится методы клонирования и т.д.
@msi про инкапсуляцию, и в частности реализацию __set()/__get(), я в курсе. Про Паблик Морозова не знал =)
@Makc если честно - ожидал Fatal error: Call to private method A::show().
Ну, а почему должен быть error?
можно вообще вот так сделать:
если имя класса объекта вызывающего метод == имени класса объекта в котором этот метод объявлен, то можно вызывать и private методы (если это тот же класс, то мы знаем что делать с ними и ничего не "попортим")
но это может всплыть много где, где есть реализация магических методов __get/__set/__call например ORM'ы и т.п., поэтому существует практика начинать названия private и protected свойств, методов с подчеркивания (_name), тогда фильтровать обращения к ним - тривиальная задача (и autocomplete сразу видно что public, а что нет)
Прочитал первые посты и проблевался, вот такой баг, бля, надо чтобы был потому что это Singleton такой, закончили институт 10 лет назад, лол. Это все баги и не доработки, синглтон? Просто надо сделать private конструктор, а получить new с помощью getInstance() и проверить статический счетчик, мудилы, а лезть внутрь private метода, никто не разрешает, ну это исправлят.
И вообще создать объект одна операция, а созданный трогать - другая.
А как объяснить вот это:
ТОЛСТО