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

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Расширение класса

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


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

> Без описания
scarzie
Отправлено: 02 Августа, 2013 - 17:20:09
Post Id


Новичок


Покинул форум
Сообщений всего: 41
Дата рег-ции: Авг. 2013  


Помог: 1 раз(а)

[+]


Здравствуйте. Есть класс, в нем есть некий функционал. Можно ли класс дополнить (расширить), добавить к нему пару методов. Но именно добавить к этому классу, не создавая классов наследников, т.е. так, чтобы я мог дальше к нему обращаться по его имени, а не по имени класса наследника.
Например:
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 классу?
 
 Top
caballero
Отправлено: 02 Августа, 2013 - 17:37:43
Post Id


Активный участник


Покинул форум
Сообщений всего: 5998
Дата рег-ции: Сент. 2011  
Откуда: Харьков


Помог: 126 раз(а)




если нигде нельзя меняь код ни в самом классе ни в месте его вызова то наверно никак
вообще какая то странная задача


-----
Бесплатная система складского учета с открытым кодом https://zippy[dot]com[dot]ua/zstore
 
 Top
scarzie
Отправлено: 02 Августа, 2013 - 17:43:18
Post Id


Новичок


Покинул форум
Сообщений всего: 41
Дата рег-ции: Авг. 2013  


Помог: 1 раз(а)

[+]


Расширить сам класс естественно надо ДО работы с ним (создания объектов). Т.е. есть класс, если выполняется определенное условие, расширяем класс - добавляем к нему все что хочется, и потом начинаем с классом работать.
Такое осуществить можно?

(Отредактировано автором: 02 Августа, 2013 - 17:43:44)

 
 Top
caballero
Отправлено: 02 Августа, 2013 - 17:45:50
Post Id


Активный участник


Покинул форум
Сообщений всего: 5998
Дата рег-ции: Сент. 2011  
Откуда: Харьков


Помог: 126 раз(а)




Цитата:
Т.е. есть класс, если выполняется определенное условие, расширяем класс - добавляем к нему все что хочется, и потом начинаем с классом работать.

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

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

(Отредактировано автором: 02 Августа, 2013 - 17:46:49)



-----
Бесплатная система складского учета с открытым кодом https://zippy[dot]com[dot]ua/zstore
 
 Top
EuGen Администратор
Отправлено: 02 Августа, 2013 - 17:47:30
Post Id


Профессионал


Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Можно:
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. Используйте это только если понимаете, для чего это нужно и что Вы делаете.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
stifard
Отправлено: 02 Августа, 2013 - 17:52:28
Post Id


Новичок


Покинул форум
Сообщений всего: 40
Дата рег-ции: Май 2013  


Помог: 1 раз(а)




EuGen пишет:
addMethod

наверное такого метода нет в mysqli
Цитата:
можно создать class Db extends mysqli{} , к нему добавить __destruct и пользоваться классом Db - это понятно. Но можно ли как-то __destruct добавить именно к mysqli классу?
 
 Top
scarzie
Отправлено: 02 Августа, 2013 - 17:58:36
Post Id


Новичок


Покинул форум
Сообщений всего: 41
Дата рег-ции: Авг. 2013  


Помог: 1 раз(а)

[+]


EuGen, большое спасибо.
Насчет того что так делать не правильно - Вы правы. Но мне кажется что это иногда просто необходимо. Причем надо расширить именно класс, а не экземпляр. В первом сообщении, как мне кажется, привел очень наглядный пример.

Как добавить к классу mysqli метод __destruct() не создавая классов потомков? В него к примеру можно было б добавить закрытие соединения.

(Отредактировано автором: 02 Августа, 2013 - 17:59:44)

 
 Top
DeepVarvar Супермодератор
Отправлено: 02 Августа, 2013 - 18:14:01
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Не забываем - если написано final class blablabla, то все - хоть обрасширяйся..
 
 Top
scarzie
Отправлено: 02 Августа, 2013 - 18:55:33
Post Id


Новичок


Покинул форум
Сообщений всего: 41
Дата рег-ции: Авг. 2013  


Помог: 1 раз(а)

[+]


DeepVarvar, это конечно само собой. Имелось ввиду что класс не заблокирован для наследования.
Я так понял что расширить/дополнить класс - нельзя.

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



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




scarzie пишет:
Разве я не прав?

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

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

Решается фабрикой. (паттерн Factory)
Но если у классов и API разный - то так вы только запутаете код.


-----
PostgreSQL DBA
 
 Top
IllusionMH
Отправлено: 02 Августа, 2013 - 19:06:42
Post Id



Активный участник


Покинул форум
Сообщений всего: 4254
Дата рег-ции: Февр. 2011  
Откуда: .kh.ua


Помог: 242 раз(а)




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. }

(Отредактировано автором: 02 Августа, 2013 - 19:07:28)

 
 Top
scarzie
Отправлено: 03 Августа, 2013 - 00:34:45
Post Id


Новичок


Покинул форум
Сообщений всего: 41
Дата рег-ции: Авг. 2013  


Помог: 1 раз(а)

[+]


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

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

да, Вы правы, не думал с этой точки зрения)
Если у кого-то еще есть что интересного сказать на эту тему - было б интересно услышать.
 
 Top
DelphinPRO
Отправлено: 03 Августа, 2013 - 02:08:47
Post Id



Активный участник


Покинул форум
Сообщений всего: 7187
Дата рег-ции: Февр. 2012  


Помог: 353 раз(а)




Базовый класс
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. // профит :)


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

(Отредактировано автором: 03 Августа, 2013 - 02:09:37)



-----
Чем больше узнаю, тем больше я не знаю.
 
 Top
scarzie
Отправлено: 03 Августа, 2013 - 02:14:01
Post Id


Новичок


Покинул форум
Сообщений всего: 41
Дата рег-ции: Авг. 2013  


Помог: 1 раз(а)

[+]


DelphinPRO, ну нифига ж себе.. Большое спасибо ;)
 
 Top
Okula
Отправлено: 03 Августа, 2013 - 02:17:52
Post Id



Участник


Покинул форум
Сообщений всего: 1389
Дата рег-ции: Окт. 2010  


Помог: 42 раз(а)




Так же можно упростить и в этой части:
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. }
 
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Вопросы новичков »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB