Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: К private методам можно получить доступ даже за пределами этого объекта?
Форумы портала PHP.SU » » Объектно-ориентированное программирование » К private методам можно получить доступ даже за пределами этого объекта?

Страниц (1): [1]
 

1. like_you - 08 Июля, 2014 - 13:53:10 - перейти к сообщению
Совсем случайно наткнулся на такой спецефект, при котором доступ к private методу можно получить даже вне объекта, который имеет этот метод. Пример
PHP:
скопировать код в буфер обмена
  1. class A{
  2.         private function priv()
  3.         {
  4.                 echo 'доступ есть';
  5.         }
  6.        
  7.         public function publ()
  8.         {
  9.                 $obj_new = new A;
  10.                 $obj_new->priv();
  11.         }
  12. }
  13.  
  14. $obj = new A;
  15. $obj->publ();

Очень интересно по какому правилу можно такое сделать. Ведь уже следующее не проходит:
PHP:
скопировать код в буфер обмена
  1. class A{
  2.         private function priv()
  3.         {
  4.                 echo 'доступ есть';
  5.         }
  6. }
  7.  
  8. class B extends A{
  9.        
  10.         public function publ()
  11.         {
  12.                 $obj_new = new B;
  13.                 $obj_new->priv();
  14.         }
  15. }
  16.  
  17. $obj = new B;
  18. $obj->publ();

Во втором примере логика запрета доступа понятна, а вот в первом... Ведь там даже не protected метод, когда можно было бы предположить, что раз объект создан на основе такого же класса, то и доступ есть...
2. Мелкий - 08 Июля, 2014 - 14:21:20 - перейти к сообщению
Доступ проверяется относительно класса, а не объекта.
В первом случае вы из класса A вызываете метод класса А - никаких проблем, потому и вызывается. И не смотрит, что объект другой.

В частности, можно вот так:
PHP:
скопировать код в буфер обмена
  1. class A{
  2.         private function priv()
  3.         {
  4.                 echo 'доступ есть';
  5.         }
  6.  
  7.         public function publ($obj_new)
  8.         {
  9.                 $obj_new->priv();
  10.         }
  11. }
  12.  
  13. $obj = new A;
  14. $obj_new = new A;
  15. $obj->publ($obj_new);

Не помню, как к этому относятся сами разработчики PHP, но я бы не рекомендовал этим пользоваться.

like_you пишет:
при котором доступ к private методу можно получить даже вне объекта, который имеет этот метод.

Начиная с 5.4 можно штатно к любому private методу или свойству получить доступ, не имея вовсе никакого отношения к этому классу... С помощью closure::bindTo.
3. like_you - 08 Июля, 2014 - 14:32:30 - перейти к сообщению
Мелкий пишет:
Доступ проверяется относительно класса, а не объекта.
Спасибо за ответ.
Прикольно, то есть, в самом классе можно использовать приватные методы разных объектов этого же класса.
4. and_07 - 08 Июля, 2014 - 14:45:32 - перейти к сообщению
del
5. EuGen - 08 Июля, 2014 - 16:10:50 - перейти к сообщению
Мелкий пишет:
Начиная с 5.4 можно штатно к любому private методу или свойству получить доступ, не имея вовсе никакого отношения к этому классу... С помощью closure::bindTo.

Нет, невозможно. Скажем,

PHP:
скопировать код в буфер обмена
  1. class Test
  2. {
  3.     private function privateMethod()
  4.     {
  5.         return 'caught';
  6.     }
  7. };
  8.  
  9. $c = function()
  10. {
  11.     return $this->privateMethod();
  12. };
  13.  
  14. $obj = new Test;
  15. $c   = $c->bindTo($obj);
  16. $c();

Вернёт вполне логичную ошибку несоответствия контекста (то есть, попытка доступа к приватному методу класса Test из контекста Closure)

Ну, а, скажем,

PHP:
скопировать код в буфер обмена
  1. class Test
  2. {
  3.     private function privateMethod()
  4.     {
  5.         return 'caught';
  6.     }
  7.  
  8.     public function publicMethod()
  9.     {
  10.         $c = function()
  11.         {
  12.                 return $this->privateMethod();
  13.         };
  14.         $c = $c->bindTo($this);
  15.         $c();
  16.     }
  17. };
  18.  
  19. $obj = new Test;
  20. $obj->publicMethod();

Будет работать - но это лишь частный случай уже рассмотренной выше проблемы, когда доступ проверяется на уровне текущего класса, а не конкретного экземпляра класса.
6. Мелкий - 08 Июля, 2014 - 16:33:44 - перейти к сообщению
EuGen пишет:
Нет, невозможно. Скажем,

7. EuGen - 08 Июля, 2014 - 16:50:01 - перейти к сообщению
Мелкий пишет:
$c = $c->bindTo($obj, $obj);

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

Вкратце - "извне" (из другого контекста) доступ получить не получится. bindTo с указанием области видимости как класса текущего экземпляра есть лишь встраивание кода замыкания в контекст этого класса.
8. Мелкий - 08 Июля, 2014 - 16:59:49 - перейти к сообщению
Опять упираемся в терминологию?
Я под "извне" подразумевал отсутствие необходимости редактировать оригинальный код класса, но при этом прочитать/записать свойство объекта либо вызвать метод, не предназначенные для публичного доступа.
9. EuGen - 08 Июля, 2014 - 17:04:54 - перейти к сообщению
Мелкий пишет:
Я под "извне" подразумевал отсутствие необходимости редактировать оригинальный код класса, но при этом прочитать/записать свойство объекта либо вызвать метод, не предназначенные для публичного доступа.

Такая задача имеет не единственный способ решения. Начиная уже озвученными замыканиями ("наиболее изящно") и заканчивая serialize + работа со строковым результатом + unserialize. Ничего нового в этом нет. Видимо, я действительно не корректно понял значение "извне", которое Вы имели ввиду.
10. teddy - 08 Июля, 2014 - 17:51:58 - перейти к сообщению
Ещё обращение к приватному методу извне(тоже, что имел ввиду Мелкий) можно реализовать с помощью Reflection API

PHP:
скопировать код в буфер обмена
  1. class MyClass
  2. {
  3.     private function sayHello($name)
  4.     {
  5.         return 'Hello, '.$name;
  6.     }
  7. }
  8.  
  9. $rMethod = new ReflectionMethod('MyClass', 'sayHello');
  10. $rMethod->setAccessible(true);
  11. echo $rMethod->invoke(new MyClass, 'Mike');//Hello, Mike
11. EuGen - 08 Июля, 2014 - 17:55:48 - перейти к сообщению
^ If you can do something then it does not mean you should do it..
В общем - никогда не следует делать такого, не важно, замыкания это или рефлекция или что-либо другое. Это полностью ломает концепцию приватных/защищённых данных.

Это в том числе и насчёт
Мелкий пишет:
Не помню, как к этому относятся сами разработчики PHP, но я бы не рекомендовал этим пользоваться.

- то есть, совершенно правильная рекомендация так не поступать. И разработчики - да, в курсе. Но есть такие вещи, как "historically-based issues", увы.
12. teddy - 08 Июля, 2014 - 18:02:23 - перейти к сообщению
EuGen пишет:
Это полностью ломает концепцию приватных/защищённых данных.

Соглашусь

Но и возражу:
Никто в этом топике не призывает делать подобные финты. Был задан конкретный вопрос и на него были даны конкретные ответы, не более.
13. LIME - 08 Июля, 2014 - 21:59:40 - перейти к сообщению
У тедди что ни пост то отражения
я б их совсем запретил

 

Powered by ExBB FM 1.0 RC1