Cześć Wszystkim :)
Pytanie jak w temacie - pochwalcie się swoim najbardziej skomplikowanym dziełem niezależnie od tego czy to coś prostego czy już trudniejsze łamigłówki ;> Oczywiście nie musicie wklejać kodu, to wasza własność intelektualna :)
A poniżej opis mojego problemu w PHP i skromnego opisu jego rozwiązania ; >
Jakiś czas temu zacząłem pisać system do zarządzania zamówieniami w firmie. Chciałem napisać na prawdę solidny kod, nauczyć się przy okazji czegoś. Na początku napisałem routing ( dla początkujących jest to funkcja klasa, która parsuje adres URI, lub GET/POST i w zależności od zapytania wywołuje odpowiednią klasę / funkcje ). Szybko okazało się, że jeśli chce wywołać klasę, która do swojego działania potrzebuję obiektu innej klasy, czy wielu klas to jest problem. Przykład kodu:
class pierwsza {}
class druga {
private $pierwsza;
public function __construct(pierwsza $pierwsza) {}
}
class trzecia {
private $druga;
public function __construct(druga $druga) {}
}
class classLoader {
public function loadClassWithDependencies($className) {
// tutaj kod za zaladowanie wybraje klasy wraz z wszystkimi jej zaleznosciami
}
}
$obj = classLoader('trzecia');
Jak widać w tym przykładzie chodzi o to, żeby metoda loadClassWithDependencies stworzyła obiekt klasy trzecia , i nie było by w tym problemu gdyby klasa trzecia nie wymagała klasy druga, która wymaga klasy pierwsza. Metoda loadClassWithDependencies ma za zadanie załadować dowolną wskazaną klasą niezależnie od ilości zależności i zależności tych zależności itd (...).
Na początku z pomocą przyszło ReflectionClass. Klasa ta umożliwia wyciągnięcie wielu informacji na temat wskazanej klasy bez konieczności jej uruchamiania. W ten sposób stworzyłem drzewo wszystkich klas powiązanych bezpośrednio, lub pośrednio z klasą docelową w tym przypadku jest to klasa trzecia. Oczywiście wymagało to użycia funkcji rekurencyjnej.
Następny krok zajął mi sporo czasu przez nieznajomość języka i try-hardowanie zamiast na chłodno spojrzeć na sprawę. Teraz mając już drzewo należy wywołać klasy w odpowiedniej kolejności z ich zależnościami. Problemem tu było to, że klasy mogą potrzebować różnej ilości zależności. Może być przypadek gdzie klasa potrzebuje 3,5,10,15 zależności. Pierwsze co pomyślałem to po prostu przekaże tablicę obiektów i się wywoła, no ale nic z tego. PHP wyrzuciło błąd - argument musi być obiektem, a nie tablicą ;)
Później przypadkiem trafiłem na funkcję eval i wpadłem na jeszcze jeden pomysł ; > Funkcja eval wykonuje kod, który jest podany jako argument typu string. Dzięki temu mogłem wygenerować potrzeby fragment kodu, coś w tym rodzaju:
$string = "new trzecia(";
foreach ($dependencies as $dependency) {
$string = $string."$dependency,";
}
$string = $string.");";
eval($string);
Powyższa pętla dodaje do zmiennej $string wszystkie zależności dla klasy trzecia, natomiast funkcja eval wywołuje zawartość zmiennej $string jako kod PHP ; > W ten sposób jest utworzona klasa z wszystkimi potrzebnymi argumentami, czyli w tym przypadku obiektami ; >
Drugim sposobem jest podobnie jak powyżej utworzenie stringa z kodem. Następnie należy zapisać ten kod do pliku file_put_contents i załadować require/include ; > Można nawet tworzyć cache, wszystkich możliwych wywołań i wtedy już wystarczy tylko ładować odpowiedni plik bez potrzeby generowania stringa z kodem ; >
Przyznam się, że to mój pierwszy tak długi post, w którym opisuje proces tworzenia czegoś więc miejcie jakieś minimum wyrozumiałości ; > A no i pierwszy post tutaj ! ; ) Jeśli macie jakieś pytania to śmiało ; >
Czekam na wasze algorytmy, z którymi się uporaliście, a może nadal z czymś walczycie niczym wojownik poeta? ;> Oczywiście nie musi nikt opisywać tego choć mile widziane jakieś wyjaśnienia, skrawki kodu ;>
Edit: nie jest to pełne rozwiązanie problemu, fragmenty kodu pisałem z palca i mają one za zadanie jedynie zarysować problem / jego wyjaśnienie / rozwiązanie.