Динамическое наследование методов класса(PHP4)

solaris

Новичок
Динамическое наследование методов класса(PHP4)

Здравствуйте!
Такая проблема.Есть такая вот схема работы:

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

index.php
PHP:
include_once ('navigator.class.php');
include_once ('acts.class.php');
$app = new navigator();
$app->run($module,method);
navigator.class.php
PHP:
.....
function run($module,$method)
{
  require_once($module."class.php");
  $class=new $module();
  $class->start($method); //функция start() является общей для всех модулей.ниже видно.
}
....
Пример модуля(example.class.php):
PHP:
 class example extends acts
 {
    function example()
    {
        ........
        $this->response='the test';
    }
   ..................
 }
acts.class.php(хранилище всех переменных и функции обработки и вывода сформированной модулями информации)
PHP:
var $response=null;
.......//все переменные нужные для обработки и вывода информации
   function start($method)
   {
       ....//подготовка данных
       if (!method_exists($this, $method)) {print "error"; exit;}
       $this->$method();
      ....//обработка данных
      print $out;
   }
......
Дык вот, схему эту менять совсем не хочется, ибо очень удобно. Но возникла одна проблема, нужно написать модуль(A), для управлениями другими модулями(B), при чем функции управления находятся во вторых.все возможные модули являются потомками класса acts, важно что, чтобы при инициализации B из A, не происходила обнуление переменных класса acts, при этом, при последуещей проверке на наличие метода из класса B в классе A, возращалось true.идеальный вариант:

PHP:
  class A extends acts
  {
        function A()
        {
            $b=new B();
            $this=$b;
         }
   }
При таком раскладе, все получается идеально, только вот обнуляются значение переменных класса acts(т.к. B является также его потомком).

Я уже запутался:((( никак не могу придумать эдакого посредника, а очень нужно:((..

Направьте на путь истинный уважаемые профессионалы пожалуйста:(

Заранее спасибо.

-~{}~ 07.05.08 13:39:

решил вот так:

PHP:
class A extends acts 
  { 
        function A() 
        { 
            $b=new B(); 
            $vars= get_object_vars($this);
             foreach($vars as $key => $v)
             {
                 $b->$key=$v;
             }
             $this=$b;
         } 
   }
 

solaris

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



а чем плохо такое решение?:
PHP:
class A extends acts  
  {  
        function A()  
        {  
            $b=new B();  
            $vars= get_object_vars($this); 
             foreach($vars as $key => $v) 
             { 
                 $b->$key=$v; 
             } 
             $this=$b; 
         }  
   }
Не, я конечно понимаю, что это не совсем изящно и красиво, именно с этой целью, я и обращался за помощью на этот форум за помощью, но увы никто не смог мне помочь:((

Есть ли какие-то действительно стремные последства при такой "подмене" класса?
 

whirlwind

TDD infected, paranoid
Стремные последствия видны уже сейчас. Если в первой половине первого топика все более-менее понятно, то во второй наоборот - все непонятно.

чтобы при инициализации B из A, не происходила обнуление переменных класса acts, при этом, при последуещей
Не знаю как там в PHP4, но в PHP5 переменные или более правильно - значения атрибутов, относятся не к классу, а к объекту класса. Из этого наверное следует что инстанцирование одного экземпляра никак не может быть связано с изменением атрибутов другого экземпляра.

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

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

solaris

Новичок
Я постараюсь показать, просто не хотелось перегружать топик кодом:)

Итак:
.htaccess в корне сайта:
PHP:
DirectoryIndex index.php
Options +FollowSymLinks +ExecCGI
<IfModule mod_rewrite.c>
  RewriteEngine On
RewriteBase /
 RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
полный текст index.php:
PHP:
<?php
define("ROOT_DIR", dirname(__FILE__));
include_once ROOT_DIR.'/config/global.conf.php';//глобальные настройки
include_once INC_DIR.'navigator.class.php';
$a= new navigator();
$a->run();
?>
О запросах: запрос вида http://site.ru/store/item -- будет обрабатывать модуль с алиасом store при этом будет запущен его метод itemAct.


navigator.php:
PHP:
<?php
class navigator{
	var $moduleName = null;
	function navigator() {
                        global $db;
		error_reporting(ER_REP);
                          ......//подключение впомогательных классов mysql, error и тд.
                         require_once (INC_DIR . 'acts.class.php'); 
		$db = new db($db_host?$db_host:'localhost',$db_user,$db_password,$db_name);
	}

	function run () {
		global $db;
		$alias = Utils::getfirstPathNode();//получаем алиас модуля из $_SERVER['REQUEST_URI']
//если модуля с таким алиасом не сущ. загружается дефолт-ый модуль
//получаем дополнительную инфу о запрашиваемом модуле пишем ее в массив $moduleInfo[0];
		$this->moduleProcessor=$moduleInfo[0]['processor'];
		$moduleFile = MODULES_DIR.$this->moduleProcessor.'Acts.class.php';
		require_once($moduleFile);
		$module = new $moduleName($moduleInfo[0]); //создаем экземпляр класса запрашиваемого модуля
		$module->start();//запускаем метод start родительского класса всех модулей
		$view = $module->getView();//запускаем метод getView родительского класса всех модулей
		$data = $view->getView();
		echo $data;
	}
}
Теперь родитель всех классов(acts.class.php) его ключевые методы( start, getView)
PHP:
class Acts{
	var $request = null;//разбитый на массив запрос(вместе с гет переменными)
	var $response = null;//сюда складываются данные от запущенного модуля(например store)
	var $options=array();//конфиг запущенного модуля(например store)
	var $post;//пост переменные
	var $libs;//массив с экземплярами классов библиотек
	var $db;
.............................
	function start(){
	    $this->getRequest();//получаем запрос заполняем соответсвующие массивы, филтруем опасные символы
		$this->actionName=$this->getActionName();//получаем имя метода который нужно запустить
		$actionName = $this->actionName.($this->response['_CP']?'Admin':'').'Act';
.............//делаем всякую чушь пока к делу не относящуюся
		$this->$actionName();//запускаем запрошенный метод из запрошенного модуля(для примера запроса: запускаем метод itemAct() класса store.class.php)
	}

	function getView(){
		include_once INCV_DIR.$this->view.'view.class.php';//класс в котором загружаются и "компилятся" шаблоны
		$view = $this->view.'View';
		return new $view($this->response); //возращаем экземпляр этого класса передав в конструктор массив с дыннми которые сформировал запрошенный модуль(например store)
	}
.............................
}
----------------------------------------
Модули:
store.class.php:
PHP:
class store extends acts
{
    function store($moduleInfo)
    {
      ................
     }

     function itemAct()//пользовательский метод получение данных
     {
       ..................
      }

     function itemAdminAct()//админский метод - редактирование данных
     {
       if(!$this->response['_CP']) exit; //если мы не админы
      ..............................................
      }
}

Дык вот суть в чем, очень хочется сделать в этом движке возможность добавления и удаления модулей. Каждый модуль включает в себя набор: из класс модуля(например store.class.php), библиотеки модуля которая содержит дополнительные общие методы модуля. Сам класс модуля, помимо пользовательских методов(то есть методы какие работают при просмотре сайта) есть еще и административные методы для редактирования данных, с которыми работает этот модуль, административные методы могут запускаться только админами.

Сама админка выполнена тоже в виде отдельного модуля. У всех модулей движка(в том числе и у админки) родитель класс acts.class.php.

О запросах в админке:
http://site.ru/admin/store/item --- говорит о том, что мы в админке, наодимся в меню редактирования модуля - store, в подменю редактирования данных которые использует метод itemAct().
при этом print_r($this->request['path'])($this->request - в классе Acts.class.php):
PHP:
array (
                     0 => [admin]
                     1 => [store]
                     2 => [item]
                  );
При чем, так как админка тоже модуль, движок не делает перед ней никаких исключений ---- то есть движок создает экземпляр класс admin.class.php, и пытается запустить в нем метод storeAct(), но класс админки понятия не имеет сколько и каких у нас модулей подключено, и сколько и каких в каждом из них методов управления. Поэтому admin.class.php, должен делать следующее:

Как только движок создал(в файле navigator.php) его экземпляр,
Найти модуль с именем store.class.php, создать его экземпляр, и унаследовать его метод itemAdminAct, затем подменить ($this->request['path'] таким образом:
PHP:
array (
                     0 => [admin]
                     1 => [item]
                  );
Чтобы движок запустил метод itemAdminAct который(по мнению движка, основанного на $this->request['path']) принадлежит классу admin.class.php... Дык вот в чем же собственно дело, если нам не удастся унаследовать itemAdminAct, или мы потеряем значение $this->request['path'], то движо выдаст нам ошибку в первом случае: что метод itemAdmAct не найден в классе admin.class.php; во втором случае движок не будет вообще знать какой метод запускать, а значит запустит дефолтный метод(indexAct) из класса admin.class.php, что будет тоже не нужным результатом.

Собственно вопрос, как написать конструктор класса admin.class.php, так чтобы он унаследовал метод itemAdminAct, и при этом не потерял значение $this->request['path']????


мой вариант плох???admin.class.php:
PHP:
class admin extends acts 
  { 
        function admin() 
        { 
          ........................... 
            $store=new store(); 
            $this=$b; 
            $vars= get_object_vars($this); 
             foreach($vars as $key => $v) 
             { 
                 $store->$key=$v; 
             } 
             $this=$store;
         } 
   }
 

whirlwind

TDD infected, paranoid
Найти модуль с именем store.class.php, создать его экземпляр, и унаследовать его метод itemAdminAct, затем подменить ($this->request['path'] таким образом:
Зачем? У вас есть рабочий модуль store. Создайте navigator для админки. Все нужные данные необходимо не наследовать изнутри, а впрыскивать снаружи.

PHP:
function start(Request $incomingRequest){
    // нам пофик, как был получен Request,
    // главное что он реализует нужный интерфейс
}
За каким чертом у вас родительский объект знает все обо всем?

[skip] многа букаф

Работайте над декомпозицией и избавляйтесь от хаков.
 

solaris

Новичок
whirlwind,



Зачем? У вас есть рабочий модуль store. Создайте navigator для админки. Все нужные данные необходимо не наследовать изнутри, а впрыскивать снаружи.
}
Пожалуй так и сделаю, спасибо, действительно удобно:)


За каким чертом у вас родительский объект знает все обо всем?

[skip] многа букаф

Работайте над декомпозицией и избавляйтесь от хаков.
Пожалуй действительно сегодня вечером сяду и все передела, вы правы, я действительно уже запустался, и прктически вновь ввел в рекурсию собственный моск:))

Спасибо огромное!
 
Сверху