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 :: Версия для печати :: Расширение класса
Форумы портала PHP.SU » » Вопросы новичков » Расширение класса

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

1. scarzie - 02 Августа, 2013 - 17:20:09 - перейти к сообщению
Здравствуйте. Есть класс, в нем есть некий функционал. Можно ли класс дополнить (расширить), добавить к нему пару методов. Но именно добавить к этому классу, не создавая классов наследников, т.е. так, чтобы я мог дальше к нему обращаться по его имени, а не по имени класса наследника.
Например:
CODE (htmlphp):
скопировать код в буфер обмена
  1. class Page{
  2.     public function login(){
  3.         return true;
  4.     }
  5. }
  6.  

При определенном условии (к примеру это админ), хотелось бы дополнить этот класс, например добавив к нему метод logout.
CODE (htmlphp):
скопировать код в буфер обмена
  1. class Page extends Page{
  2.     public function logout(){
  3.         return true;
  4.     }
  5. }

Возможно ли это как-то сделать?
Спасибо.
(Добавление)
Придумал хороший пример. Как добавить к mysqli метод __destruct() ?
То что можно создать class Db extends mysqli{} , к нему добавить __destruct и пользоваться классом Db - это понятно. Но можно ли как-то __destruct добавить именно к mysqli классу?
2. caballero - 02 Августа, 2013 - 17:37:43 - перейти к сообщению
если нигде нельзя меняь код ни в самом классе ни в месте его вызова то наверно никак
вообще какая то странная задача
3. scarzie - 02 Августа, 2013 - 17:43:18 - перейти к сообщению
Расширить сам класс естественно надо ДО работы с ним (создания объектов). Т.е. есть класс, если выполняется определенное условие, расширяем класс - добавляем к нему все что хочется, и потом начинаем с классом работать.
Такое осуществить можно?
4. caballero - 02 Августа, 2013 - 17:45:50 - перейти к сообщению
Цитата:
Т.е. есть класс, если выполняется определенное условие, расширяем класс - добавляем к нему все что хочется, и потом начинаем с классом работать.

полная чушь. что это за расширение класса по условию?

по условию можно создавать тот или иной екземпляр класса
для этого можно сделать фабричный метод который будет возвращать екземпляр нужного типа.
5. EuGen - 02 Августа, 2013 - 17:47:30 - перейти к сообщению
Можно:
PHP:
скопировать код в буфер обмена
  1. class Test
  2. {
  3.    protected $_rgMethods = [];
  4.    
  5.    public function addMethod($sName, $mCode, $mArgs=null)
  6.    {
  7.       if(!is_string($sName) || !preg_match('/^[a-z_][a-z0-9_]*$/i', $sName))
  8.       {
  9.          throw new Exception('Invalid method name format');
  10.       }
  11.       if(is_string($mCode) && !($mCode = @create_function($mArgs, $mCode)))
  12.       {
  13.          throw new Exception('Passed string is not a valid code');
  14.       }
  15.       if(is_callable($mCode))
  16.       {
  17.          $this->_rgMethods[$sName]=$mCode;
  18.          return true;
  19.       }
  20.       throw new Exception('Passed data is not a valid callback');
  21.  
  22.    }
  23.  
  24.    public function __call($sName, $rgArgs)
  25.    {
  26.       if(array_key_exists($sName, $this->_rgMethods))
  27.       {
  28.          return call_user_func_array($this->_rgMethods[$sName], $rgArgs);
  29.       }
  30.       throw new Exception('General error: call of unregistered method '.$sName.'()');
  31.    }
  32. }
  33.  
  34. $rObj = new Test();
  35. $fnMethod = function($x, $y)
  36. {
  37.    return $x+$y;
  38. };
  39. $rObj->addMethod('getSum', $fnMethod);
  40. var_dump($rObj->getSum(3, 10));

- но не нужно.
Заметьте, что речь идёт о "расширении" в контексте экземпляра, но не класса. Если нужно расширить сам класс, то Вам нужна библиотека RunKit и её runkit_method_add - но это очень плохая практика.
Ещё альтернатива:
PHP:
скопировать код в буфер обмена
  1. class Test
  2. {
  3.    protected static $_rgMethods = [];
  4.    
  5.    public function addMethod($sName, $mCode, $mArgs=null)
  6.    {
  7.       if(!is_string($sName) || !preg_match('/^[a-z_][a-z0-9_]*$/i', $sName))
  8.       {
  9.          throw new Exception('Invalid method name format');
  10.       }
  11.       if(is_string($mCode) && !($mCode = @create_function($mArgs, $mCode)))
  12.       {
  13.          throw new Exception('Passed string is not a valid code');
  14.       }
  15.       if(is_callable($mCode))
  16.       {
  17.          self::$_rgMethods[$sName]=$mCode;
  18.          return true;
  19.       }
  20.       throw new Exception('Passed data is not a valid callback');
  21.  
  22.    }
  23.  
  24.    public function __call($sName, $rgArgs)
  25.    {
  26.       if(array_key_exists($sName, self::$_rgMethods))
  27.       {
  28.          return call_user_func_array(self::$_rgMethods[$sName], $rgArgs);
  29.       }
  30.       throw new Exception('General error: call of unregistered method '.$sName.'()');
  31.    }
  32. }
  33.  
  34. $rObj = new Test();
  35. $fnMethod = function($x, $y)
  36. {
  37.    return $x+$y;
  38. };
  39. $rObj->addMethod('getSum', $fnMethod);
  40. var_dump($rObj->getSum(3, 10));
  41. $rNew = new Test();
  42. var_dump($rObj->getSum(2, 11));

- без runkit. Используйте это только если понимаете, для чего это нужно и что Вы делаете.
6. stifard - 02 Августа, 2013 - 17:52:28 - перейти к сообщению
EuGen пишет:
addMethod

наверное такого метода нет в mysqli
Цитата:
можно создать class Db extends mysqli{} , к нему добавить __destruct и пользоваться классом Db - это понятно. Но можно ли как-то __destruct добавить именно к mysqli классу?
7. scarzie - 02 Августа, 2013 - 17:58:36 - перейти к сообщению
EuGen, большое спасибо.
Насчет того что так делать не правильно - Вы правы. Но мне кажется что это иногда просто необходимо. Причем надо расширить именно класс, а не экземпляр. В первом сообщении, как мне кажется, привел очень наглядный пример.

Как добавить к классу mysqli метод __destruct() не создавая классов потомков? В него к примеру можно было б добавить закрытие соединения.
8. DeepVarvar - 02 Августа, 2013 - 18:14:01 - перейти к сообщению
Не забываем - если написано final class blablabla, то все - хоть обрасширяйся..
9. scarzie - 02 Августа, 2013 - 18:55:33 - перейти к сообщению
DeepVarvar, это конечно само собой. Имелось ввиду что класс не заблокирован для наследования.
Я так понял что расширить/дополнить класс - нельзя.

Дальше оффтоп и ИМХО:
Допустим есть класс Forum который выводит темы, сообщения, категории и т.д.
Админ может редактировать сообщения, удалять темы, банить ну администрировать в общем. Зачем делать класс потомок, и придумывать ему имя что-то на подобии "Forum_admin", если можно было б просто дополнить класс Forum и обращаться к нему, а не к Forum_admin?
Ну или взять и просто дополнить какой-то класс методами (тот-же mysqli, к примеру)...
Разве я не прав?
10. Мелкий - 02 Августа, 2013 - 19:05:20 - перейти к сообщению
scarzie пишет:
Разве я не прав?

Задумайтесь над тем, как вы это будете сопровождать. ООП и так имеет достаточно средств основательно запутать исходный код. А если за одним именем класса будет скрываться десяток разных реализаций? А если ещё и одновременно?

scarzie пишет:
и обращаться к нему, а не к Forum_admin?

Решается фабрикой. (паттерн Factory)
Но если у классов и API разный - то так вы только запутаете код.
11. IllusionMH - 02 Августа, 2013 - 19:06:42 - перейти к сообщению
scarzie, ИМХО в методе можно проверять права доступа и давать соответствующий ответ.
PHP:
скопировать код в буфер обмена
  1. class RandomClass {
  2.  
  3. //...
  4.         public function random_method( $arg ) {
  5.                 if ( ! user_can( 'edit' ) ) {
  6.                         return "You can't edit this post";
  7.                 }
  8.  
  9.                 $edit_link = get_link( $arg );
  10.                 return '<a href = "' . $edit_link . '">Edit post</a>';
  11.         }
  12.  
  13. //...
  14. }
12. scarzie - 03 Августа, 2013 - 00:34:45 - перейти к сообщению
IllusionMH, это понятно, костылей можно много прикрутить. Речь идет (точнее шла) именно об расширении класса, но увы, штатными способами этого сделать нельзя.

Мелкий пишет:
Задумайтесь над тем, как вы это будете сопровождать. ООП и так имеет достаточно средств основательно запутать исходный код. А если за одним именем класса будет скрываться десяток разных реализаций? А если ещё и одновременно?

да, Вы правы, не думал с этой точки зрения)
Если у кого-то еще есть что интересного сказать на эту тему - было б интересно услышать.
13. DelphinPRO - 03 Августа, 2013 - 02:08:47 - перейти к сообщению
Базовый класс
PHP:
скопировать код в буфер обмена
  1. namespace myapp\core;
  2.  
  3. class Page{
  4.     public function login(){
  5.         return true;
  6.     }
  7. }


наследник с тем же именем в другом пространстве имен
PHP:
скопировать код в буфер обмена
  1. namespace myapp\user;
  2.  
  3. class Page extends myapp\core\Page{
  4.     public function logout(){
  5.         return true;
  6.     }
  7. }


используем;

PHP:
скопировать код в буфер обмена
  1. use myapp\user;
  2.  
  3. $page = new Page();
  4. $page->logout();
  5. // профит :)


зы. класс-наследник конечно же присутствует, но мы можем вызывать его по имени базового класса. что и требовалось топикстартеру.
зыы. согласен с Мелким - так делать не стоит.
14. scarzie - 03 Августа, 2013 - 02:14:01 - перейти к сообщению
DelphinPRO, ну нифига ж себе.. Большое спасибо ;)
15. Okula - 03 Августа, 2013 - 02:17:52 - перейти к сообщению
Так же можно упростить и в этой части:
PHP:
скопировать код в буфер обмена
  1. namespace myapp\user;
  2. use myapp\core\Page as cPage;
  3.  
  4. class Page extends cPage {
  5.     public function logout(){
  6.         return true;
  7.     }
  8. }

 

Powered by ExBB FM 1.0 RC1