Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Wywoływanie metody tylko z zewnątrz
Forum PHP.pl > Forum > PHP > Object-oriented programming
starach
Właśnie ponad 2 godziny spędziłem na odpluskwianiu mojego fw z debilnego błędu.
Mój Loader który zajmuje się wywoływanie kontrolera, ma też za zadanie pobrać z niego widok i model. Po czym wykonać model i wrzucić wynik do widoku. Oczywiście inteligentnie w celach testowych napisałem jedną cholerną linijkę w widoku ( dodawanie danych ) żeby sprawdzić czy wyświetli. Tak wiem błąd logiczny architektury MVC, ale to miał być tylko test. W efekcie Loader nadpisywał mi oczywiście dane i nie wiedziałem dlaczego. sciana.gif

Czy da się w jakiś magiczny sposób zablokować wywoływanie metody z klasy w której ona się znajduje?
W tym wypadku chciałbym żeby klasa SDL_View nie miała dostępu do swojej metody assign(). Oczywiście po południu przeprogramuję metody dzieląc je na assign() które będzie dodawało dane do istniejących i clear() które je będzie czyściło, ale tak czy siak dobrze by było to wywołanie zablokować.

Sorry za to masło maślane powyżej ale już ledwo na oczy patrzę.
mike
Zamiast brnąć z jednych głupich pomysłów w kolejne przepisz to od nowa.
Przecież to co opisujesz to jakiś spaghetti code.
SirZooro
Jedyne rozwiązanie które mi się nasuwa to umieszczenie metody w klasie bazowej jako metody prywatnej.
phpion
Cytat(SirZooro @ 13.12.2008, 12:23:59 ) *
Jedyne rozwiązanie które mi się nasuwa to umieszczenie metody w klasie bazowej jako metody prywatnej.

Autorowi chyba chodzi o coś dokładnie odwrotnego: zablokowanie wywołania metody z klasy, a umożliwienie wywołania tylko z zewnątrz. Osobiście nie mam pojęcia jak to zrobić (o ile jest to oczywiście w ogóle możliwe).
Morkai
Da się to uzyskać poprzez odpowiednie obrobienie wyniku debug_backtrace()" title="Zobacz w manualu PHP" target="_manual, ale sensu podobnie jak mike nie widzę winksmiley.jpg

  1. <?php
  2.  
  3. function check_caller()
  4. {
  5.    $backtrace = debug_backtrace();
  6.    
  7.    if (!isset($backtrace[2]) || ($backtrace[1]['class'] === (isset($backtrace[2]['class']) ? $backtrace[2]['class'] : null)))
  8.    {
  9.        throw new BadMethodCallException();
  10.    }
  11. }
  12.  
  13. ?>


Użycie
  1. <?php
  2.  
  3. class Foo
  4. {
  5.    function doSmth()
  6.    {
  7.        $this->doFoo();
  8.    }
  9.    
  10.    function doFoo()
  11.    {
  12.        check_caller();
  13.        
  14.        echo __FUNCTION__, "\n";
  15.    }
  16. }
  17.  
  18. class Bar
  19. {
  20.    private $foo;
  21.    
  22.    function __construct(Foo $foo)
  23.    {
  24.        $this->foo = $foo;
  25.    }
  26.    
  27.    function doBar()
  28.    {
  29.        $this->foo->doFoo();
  30.    }
  31. }
  32.  
  33. function do_baz(Foo $foo)
  34. {
  35.    $foo->doFoo();
  36. }
  37.  
  38. $foo = new Foo();
  39. $bar = new Bar($foo);
  40.  
  41. echo '<pre>';
  42. try { $foo->doFoo(); } catch (BadMethodCallException $x) { echo $x, "\n"; }
  43. try { $foo->doSmth(); } catch (BadMethodCallException $x) { echo $x, "\n"; }
  44. try { $bar->doBar(); } catch (BadMethodCallException $x) { echo $x, "\n"; }
  45. try { do_baz($foo); } catch (BadMethodCallException $x) { echo $x, "\n"; }
  46. echo '</pre>';
  47.  
  48. ?>
starach
Cytat(mike @ 13.12.2008, 09:38:31 ) *
Zamiast brnąć z jednych głupich pomysłów w kolejne przepisz to od nowa.
Przecież to co opisujesz to jakiś spaghetti code.
  1. <?php
  2. final class DRA_Loader_Module_Collection extends SDL_Collection
  3. {
  4.    /**
  5.      * Appends new value
  6.      * @param DRA_Loader_Module $module
  7.      */
  8.    public function append(DRA_Loader_Module $module)
  9.    {
  10.        $this->_append($module);
  11.    }
  12.    /**
  13.      * Runs all modules controllers
  14.      */
  15.    public function init()
  16.    {
  17.        foreach($this as $module)
  18.        {
  19.            /* @var $module DRA_Loader_Module */
  20.            if($module->doTrigger())
  21.            {
  22.                $module->getObject()->init();
  23.                
  24.                $view = $module->getObject()->view();
  25.                $model = $module->getObject()->model();
  26.                // Check if required objects are correct
  27.                if(!is_object($model) || !DRA_Class::doesImplements($model, array('SDLi_Model')))
  28.                {
  29.                    throw new Error('LOADER_MODULE_MODEL_INCORRECT', array('model' => get_class($model)));
  30.                }
  31.                if(!is_object($view) || !DRA_Class::doesImplements($view, array('SDLi_View', 'SDLi_Initializable')))
  32.                {
  33.                    throw new Error('LOADER_MODULE_VIEW_INCORRECT', array('view' => get_class($view)));
  34.                }
  35.  
  36.                $view->init();
  37.  
  38.                // Gather data from Model and assign them to view
  39.                $view->assign($model->perform());
  40.                // Create new website main frame and assign view output to it
  41.                $frame = new DRA_Website_Frame();
  42.                $frame->setId(DRA_Website_Frame::CENTER);
  43.                $frame->setContent($view->create());
  44.                DRA_Engine::website()->frames()->append($frame);
  45.            }
  46.        }
  47.    }
  48. }
  49. ?>
Skoro to jest spaghetti code to dlaczego wiesz co tutaj się dzieje bez większego opisywania tego mike? tongue.gif
DRA_Loader pobiera przetworzony url z DRA_Router i w ten sposób ustala klasę kontrolera głównego którą zapisuje w tej kolekcji.

@Morkai: Też myślałem o debug_backtrace ale mam dziwne wrażenie że tego sposobu zastosować nie należy. Tylko cholera jakoś uzasadnienia nie mogę znaleźć. Chyba tylko mogę się podeprzeć spadkiem wydajności. Bo MVC zamierzam stosować też we wtyczkach a co za tym idzie klasę SDL_View implementującą SDLi_View będzie rozszerzać kilka może kilkanaście klas.

p.s. Później sprawdzanie czy kontroler jest 'wywoływalny'
  1. <?php
  2. if($module->doTrigger())
  3.            {
  4. ?>
, mam zamiar też wprowadzić po uruchomieniu metody init kontrolera.
Celem umożliwienia kontrolerowi zatrzymania wywoływania siebie samego.

edit>
Oczywiście Morkai za przykład wykorzystania debug_backtrace() zasłużone pomógł.
Swoją drogą może macie jeszcze jakieś inne pomysły na implementację czwartego modyfikatora dostępu external? tongue.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.