Witam. Tworzę mechanizm routingu, który ma za zadanie wywołać metodę klasy kontrolera w przypadku, gdy Router znajdzie w niej dopasowanie do ścieżki url w żądaniu GET. Wygląda to tak, że każda z metod klasy kontrolera musi zwracać tablicę, w której zawarta jest również ścieżka potrzebna do wywołania tej metody. Wszystko działa lecz problem powstaje w momencie, gdy w wywołanej metodzie kontrolera utworzę ponownie obiekt RouteCollection i wywołam metodę getallroutes() z klasy RouteCollection, z której również korzysta klasa Routera. Wtedy powstaje nieskończona pętla i na końcu wyskakuje komunikat: "Allowed memory size of 134217728 bytes exhausted (tried to allocate 262144 bytes)". Problem tkwi w metodzie getallroutes, która aby pobrać wszystkie ścieżki routingu musi pobrać informacje z metod wszystkich kontrolerów i dodać je do tworzonej tablicy routingu.
Poniżej wrzucam pliki klasy Router, Routecollection i przykłądowego kontrolera:
Router.php
<?php
require 'usingclasses/RouteCollection.php';
require 'controller.php';
require 'usingclasses/RenderRouteView.php';
class Router
{
private $urlpath;
private $request;
private $dir = 'scripts/controllers/';
private $collection;
public function __construct
($urlpath, array $request) {
$this->urlpath = $urlpath;
$this->request = $request;
$this->collection = new RouteCollection();
$this->collection = $this->collection->getallroutes(); //tablica routingu
}
/**
* @return array
*/
private function parseurl()
{
$url = explode('/', $this->urlpath);
return $url;
}
/**
* creates Controller's and View's object matched to url path
*
* @return mixed|null
* @throws Exception
*/
public function findroutecontroller() //metoda inicjująca pracę routera
{
foreach($this->collection as $routepath => $routename) //przetwarzanie tablicy routingu
{
if($routepath == implode('/', $this->parseurl())) {
$viewob = new RenderRouteView($this->collection[$routepath]['view'],$this->collection[$routepath]['args']); // mało istotne
return $viewob->renderview();
}
}
}
}
RouteCollection.php
<?php
class RouteCollection
{
private $directory = 'scripts/controllers/';
private $routecollection = [];
private $array = [];
/**
* Odpowiada za tworzenie tablicy [ścieżka/routingu => nazwa_routy]
*
* @return array
* @throws Exception
*/
public function getallroutes()
{
foreach ($this->getdirfiles($this->directory) as $dirfile)
{
$ob = $this->createobjectfromdirfile($dirfile); // Tworzy dynamicznie obiekt kontrolera który chyba nie jest usuwany
$obmethods = $this->getobjectmethods($ob);
foreach ($obmethods as $method) { // pętla z metodami aktualnie przetwarzanego kontrolera
if(!$this->getrepeatemethoddata($this->array, $ob->$method())) {
$this->array[$ob->$method()['route']] = $ob->$method(); // tworzenie tablicy [ścieżka/routingu => nazwa_routy]
}
}
}
}
return $this->array;
}
private function getdirfiles($dir)
{
return scandir($this->directory);
}
private function createobjectfromdirfile($file)
{
if(is_file($this->directory.$file)) { $cutfilename = explode('.php', $file);
require_once $this->directory.$file;
$ob = new $cutfilename[0]();
return $ob;
}
return null;
}
private function getobjectmethods($object)
{
$arr = [];
{
$arr = get_class_methods($object);
return $arr;
}
return $arr;
}
private function getrepeatemethoddata
(array $array, $method) {
{
}
{
throw new Exception('repeated keys');
}
{
}
{
throw new Exception('repeated values');
}
return false;
}
}
examplecontroller.php
<?php
require 'scripts/usingclasses/CreateForm.php';
class examplecontroller extends Controller
{
/**
* @return array
* @throws Exception
*/
public function someactionother()
{
$createform = new CreateForm();
$cos = $this->getcollection();
$form = $createform
->addformfield('input', 'login', 'Podaj login')
->addformfield('input', 'haslo', 'Podaj hasło')
->addformfield('submit', 'zapisz')
->renderform();
return $this->generaterouteargs('ma', 'jakas_routa', 'a.php', ['form'=> 'aa']);
}
private function getcollection()
{
$arr = [];
$dane = new RouteCollection();
$d = $dane->getallroutes();
return $d;
}
}
Wszystko wywołuję w pliku index.php:
index.php
<?php
require 'scripts/Router.php';
$path = !empty($_GET['path'])?
$_GET['path']: null; $router = new Router($path, $_REQUEST);
$router->findroutecontroller();
Wydaje mi się, że problem tkwi przy dynamicznym tworzeniu objektów kontrolera w 20 linii pliku RouteCollection.php czyli:
$ob = $this->createobjectfromdirfile($dirfile);
Niestety aby pobrać informacje o metodach kontrolera w postaci tablicy to muszę najpierw utworzyć obiekt klasy kontrolera ale on chyba nie jest później niszczony przy kolejnym przebiegu pętli.
Edit:Rozwiązałem mój problem. Cały problem tkwił w momencie tworzenia tablicy w której przywoływałem wszystkie metody dla utworzonego obiektu co najwidoczniej pochłaniało sporo pamięci. Rozwiązanie wygląda tak:
public function getallroutes()
{
$arr =[];
foreach ($this->getdirfiles($this->directory) as $file) {
if(is_object($this->createobjectfromdirfile($file))) { $arr[get_class($this->createobjectfromdirfile($file))] = [
'class' => $this->createobjectfromdirfile($file),
'methods' => $this->getobjectmethods($this->createobjectfromdirfile($file))
];
}
}
return $arr;
}
Zamiast wywoływać metody to utworzyłem tablicę z obiektem klasy kontrolera pod kluczem 'class' oraz tablicą metod pod kluczem 'methods'. Wszystko wywołałem dopiero w klasie Router w taki sposób:
foreach($this->collection as $iterate => $data) {
$ob = $this->collection[$iterate];
foreach ($ob['methods'] as $method) {
$classmethod = $ob['class']->$method();
if ($classmethod['route'] == implode('/', $this->parseurl())) { $view = new RenderRouteView($classmethod['view'], $classmethod['args']);
return $view->renderview();
}
}
}
Utworzyłem zmienną $ob w celu przywołania kolekcji dla danej iteracji. Później wywołałem tablicę array i z metodami dla danej iteracji i następnie wywoływałem metody w drugiej pętli. Nie wiem tylko czy jeśli będzie bardzo dużo metod do przejrzenia w danym kontrolerze (bo żeby porównać ścieżkę z metody ze ścieżką ze zmiennej get, muszę wywoływać kolejne metody kontrolera) to czy znowu nie zabraknie pamięci?
Ten post edytował emillo91 7.08.2018, 21:53:48