Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Jak szybko dostać się do wartości wielowymiarowej tablicy z poziomu metody obiektu, Tablica istnieje w obiekcie i można się dostać do niej przez metodę
adbacz
post
Post #1





Grupa: Zarejestrowani
Postów: 532
Pomógł: 24
Dołączył: 15.04.2011
Skąd: Kalisz

Ostrzeżenie: (0%)
-----


Załóżmy, że mamy wielowymiarową tablicę, której struktury do końca nie znamy. Korzysta z niej kilka innych obiektów, mogą one wstawiać do tej tablicy wartości pod odpowiednimi indeksami, ale i też je wyciągać (zakładamy, że nigdy nikt sobie na wzajem danych nie nadpisze). Ale ta tablica ma być "zarządzalna" przez osobny obiekt. To znaczy, by pobrać jakąś wartość trzeba użyć metody $object->get('index'), a żeby wstawić $object->set('index', 2). Nigdy nie ma bezpośredniego dostępu do tej tablicy.

Jak wykonać metody pobierania i wstawiania do tablicy, by były możliwie jak najszybsze (operacje na stringach to jakaś masakra w PHP ;/) i żeby można było dostać się do tablicy wgłąb, na przykład: $table['index1']['index2']['index3']?

Wymyśliłem, by na poczekaniu tworzyć funkcję anonimową (create_function), której prześlemy całą tablicę, a w stringu stworzymy już indeks do pobrania:

  1. $index = "['".implode("']['", explode('.', $index))."']";
  2. $function = create_function('$array', 'return (isset($array'.$index.') ? $array'.$index.' : null);');
  3. return $function($array);


I teraz, jeśli chcemy pozyskać jakąś wartość to w parametrze metody podajemy ciąg znaków: 'index1.index2.index3'. Ale nie jest to zbyt szybkie.

Macie może inne pomysły na rozwiązanie tego problemu?

Ten post edytował adbacz 9.07.2014, 23:26:52
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 18)
SmokAnalog
post
Post #2





Grupa: Zarejestrowani
Postów: 1 707
Pomógł: 266
Dołączył: 3.07.2012
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Najprościej, choć niezbyt elegancko, wytłumić błędy:
  1. $data = array();
  2. $element = @$data['animals']['dog']['name']; // NULL


A nie możesz spłaszczyć tej tablicy? Co ona zawiera?
Go to the top of the page
+Quote Post
by_ikar
post
Post #3





Grupa: Zarejestrowani
Postów: 1 798
Pomógł: 307
Dołączył: 13.05.2009
Skąd: Gubin/Wrocław

Ostrzeżenie: (0%)
-----


Można do tego dojść na kilka sposbów, można używać kropek pomiędzy indexami, a można zrobić to tak:

  1. <?php
  2.  
  3. class Object
  4. {
  5. protected $data = array();
  6.  
  7. public function __construct(array $array = array())
  8. {
  9. $this->data = $array;
  10. }
  11.  
  12. public function has($name)
  13. {
  14. return array_key_exists($name, $this->data);
  15. }
  16.  
  17. public function get($name, $default = null)
  18. {
  19. if($this->has($name))
  20. {
  21. if(is_array($this->data[$name]))
  22. {
  23. return new static($this->data[$name]);
  24. } else
  25. {
  26. return $this->data[$name];
  27. }
  28. }
  29.  
  30. return $default;
  31. }
  32.  
  33. public function set($name, $value)
  34. {
  35. $this->data[$name] = $value;
  36. }
  37.  
  38. public function all()
  39. {
  40. return $this->data;
  41. }
  42. }
  43.  
  44. $obj = new Object();
  45.  
  46. var_dump($obj->get('something'));
  47.  
  48. $obj->set('something', 'some value');
  49.  
  50. var_dump($obj->get('something'));
  51.  
  52. $array = array(
  53. 'key' => 'value',
  54. 'key2' => array(
  55. 'key3' => 'value3',
  56. )
  57. );
  58.  
  59. $obj2 = new Object($array);
  60.  
  61. var_dump($obj2->get('key2')->get('key3'));


Do czegoś takiego można jeszcze dodać metodę magiczną i uzyskać trochę "magii":

  1. <?php
  2.  
  3. class Object
  4. {
  5. protected $data = array();
  6.  
  7. public function __construct(array $array = array())
  8. {
  9. $this->data = $array;
  10. }
  11.  
  12. public function has($name)
  13. {
  14. return array_key_exists($name, $this->data);
  15. }
  16.  
  17. public function get($name, $default = null)
  18. {
  19. if($this->has($name))
  20. {
  21. if(is_array($this->data[$name]))
  22. {
  23. return new static($this->data[$name]);
  24. } else
  25. {
  26. return $this->data[$name];
  27. }
  28. }
  29.  
  30. return $default;
  31. }
  32.  
  33. public function __get($name)
  34. {
  35. return $this->get($name);
  36. }
  37.  
  38. public function set($name, $value)
  39. {
  40. $this->data[$name] = $value;
  41. }
  42.  
  43. public function all()
  44. {
  45. return $this->data;
  46. }
  47. }
  48.  
  49. $obj = new Object();
  50.  
  51. var_dump($obj->something);
  52.  
  53. $obj->set('something', 'some value');
  54.  
  55. var_dump($obj->something);
  56.  
  57. $array = array(
  58. 'key' => 'value',
  59. 'key2' => array(
  60. 'key3' => 'value3',
  61. )
  62. );
  63.  
  64. $obj2 = new Object($array);
  65.  
  66. var_dump($obj2->key2->key3);


I nie jest to wcale takie trudne..
Go to the top of the page
+Quote Post
SmokAnalog
post
Post #4





Grupa: Zarejestrowani
Postów: 1 707
Pomógł: 266
Dołączył: 3.07.2012
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Pytanie tylko po co tak kombinować. Moim zdaniem to jest jeden z bardzo niewielu przypadków, gdzie lepiej użyć operatora @. Efekt jest ten sam, tylko PHP wypluje błąd (stłumiony) zamiast sprawdzać "ręcznie" te indeksy. Świat się nie zawali od operatora @.
Go to the top of the page
+Quote Post
by_ikar
post
Post #5





Grupa: Zarejestrowani
Postów: 1 798
Pomógł: 307
Dołączył: 13.05.2009
Skąd: Gubin/Wrocław

Ostrzeżenie: (0%)
-----


Widzisz, operator wytłumienia nie powinno się nigdy używać, czasami zachodzi taka potrzeba jak robimy coś na kolanie. Ten operator działa tak że wytłumia błąd, tzn ty go nie widzisz, ale ten błąd się nadal generuje, jak masz jakiegoś handlera, to jest on wywoływany, tyle że jest on "ukryty". Niech teraz takich błędów będzie wytłumione 20 razy, wtedy twój handler jest wywoływany 20 razy. Czyli zużyte zasoby są dużo większe. Dodatkowo kompiler opcode (kto w ogóle nie używa opcachera ?) przechowuje taki kawałek kodu w postaci 2-3 razy obszerniejszej. Jaki sens ma skrócenie kodu do 1 znaku, jeżeli jego wymagania będą takie jakby się użyło funkcji/klasy?

Pozatym autor chciał coś obiektowego, co by sugerował jego pierwszy post..
Go to the top of the page
+Quote Post
SmokAnalog
post
Post #6





Grupa: Zarejestrowani
Postów: 1 707
Pomógł: 266
Dołączył: 3.07.2012
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Cytat(by_ikar @ 10.07.2014, 11:44:58 ) *
Widzisz, operator wytłumienia nie powinno się nigdy używać

Też tak uważałem, ale jednak nie warto popadać w skrajność. Jeśli jest używany z głową, to w czym problem? Traktowanie błędu jak jakiegoś kataklizmu jest dziwne. To lepiej kombinować z jakimiś rozwiązaniami typu kropki w indeksach niż po prostu powiedzieć interpreterowi: "jest w porządku, jeśli tu wyrzucisz błąd, bo wiem że będzie chodzić o brak klucza"? Małpa w tym kontekście ma w sobie coś fajnego, tzn.:

  1. $tablica['klucz1']['klucz2'] // mam nadzieję, że te dane tu są - jeśli nie, to wyrzuć błąd
  2.  
  3. @$tablica['klucz1']['klucz2'] // nie wiem czy te dane tu są czy nie, jak nie ma to w porządku


Zalecam zdrowy rozsądek zawsze i wszędzie.

Jesteś pewien, że handlery błędów się wywołują przy stłumionych błędach?
Go to the top of the page
+Quote Post
nospor
post
Post #7





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Cytat
Jesteś pewien, że handlery błędów się wywołują przy stłumionych błędach?
Jak najbardziej. I jesli w handlerze nie masz ustawionego, by nie lapal tlumionych, to handler bedzie ci normalnie je obslugiwal. Jesli bedziesz zapisywal do do pliku te bledy to plik bedzie pochl i pochl......
Go to the top of the page
+Quote Post
SmokAnalog
post
Post #8





Grupa: Zarejestrowani
Postów: 1 707
Pomógł: 266
Dołączył: 3.07.2012
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Pytanie tylko kto zapisuje w pliku błędy typu notice. (IMG:style_emoticons/default/smile.gif) Ja uwielbiam tego typu dyskusje, można poznać różne punkty widzenia. Nie jestem fanatykiem ani jednego, ani drugiego wyjścia. Złotym środkiem może się okazać używanie klasy typu Collection, które mogą oferować wiele przydatnych funkcji nieobecnych domyślnie dla tablic. Tak sobie pomyślałem, że takie skomplikowane i nieobliczalne struktury to już może być trochę za dużo dla tablicy.
Go to the top of the page
+Quote Post
nospor
post
Post #9





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Cytat
Pytanie tylko kto zapisuje w pliku błędy typu notice
Hmm.... moze porządny programista, ktory zdaje sobie sprawe z tego ze jest tylko czlowiekiem i ze moze gdzies popelnic glupi blad, ktorego nie zauwazy?
To prawda, ze akurat w tym przypadku NOTICE to zwykla niechciana popierdulka ale ogolnie bledy NOTICE to cala gama bledow i wbrew pozorom mogą wskazywac na blad, ktory moze miec kolosalne skutki.
Go to the top of the page
+Quote Post
by_ikar
post
Post #10





Grupa: Zarejestrowani
Postów: 1 798
Pomógł: 307
Dołączył: 13.05.2009
Skąd: Gubin/Wrocław

Ostrzeżenie: (0%)
-----


Nie trzeba być fanatykiem żadnego rozwiązania. Ale logowanie każdego rodzaju błędów, bo przecież tego błędu w aplikacji nie wyświetlisz jest wymagane, bez względu na to jakie twoje podejście jest. Albo coś robisz i masz nad tym kontrole, albo to żyje swoim życiem. Tak wywoływanie handlera 20 razy jest bardziej optymalne niż prosta klasa.. No raczej nie, bo cały "stack" jest wtedy generowany 20 razy. A do tego mojego "prostego" rozwiązania, mogę kontrolować co będzie mi zwracać dana zmienna, jeżeli dany klucz nie istnieje.
Go to the top of the page
+Quote Post
Crozin
post
Post #11





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Możesz skorzystać z całkiem przyzwoitego komponentu PropertyAccess z Symfony, ale przede wszystkim powinieneś w ogóle zmienić podejście. Wielowymiarowa tablica, gdzie coś może istnieć bądź nie, czego nawet w pewnym sensie nie chce Ci się sprawdzać... to doprowadzi jedynie do ogromnego bałaganu i niestabilności w działaniu systemu.

Cytat
Pytanie tylko kto zapisuje w pliku błędy typu notice.
Pojawienie się notice'a powinno w zdecydowanej większości przypadków skutkować wywaleniem całego systemu, bo w tym momencie, zachowuje się on w sposób nieprzewidziany.
Go to the top of the page
+Quote Post
Sephirus
post
Post #12





Grupa: Zarejestrowani
Postów: 1 527
Pomógł: 438
Dołączył: 28.06.2011
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


Trochę OT ale moim zdaniem całe to zadanie nie ma najmniejszego sensu...

Ja to widzę bardziej jako tzw. rejestr w aplikacji - każdy moduł/obiekt może z niego korzystać bo jest dostępny ogólnie. Jeśli z kolei każdy obiekt korzysta tak jak pisał autor czyli nie nadpisując sobie niczego to tym bardziej rejestr się nadaje - każdy obiekt trzyma w nim dane, które sam zmienia - inne mogą odczytywać. Nie widzę sensu w takim udziwnianiu bo nic to nie daje (IMG:style_emoticons/default/smile.gif) Mogłoby dawać blokowanie edycji ( dana ścieżka dostępna tylko dla określonego obiektu) tylko po co pisać coś od nowa jak mamy takie coś jak ACL...

Sposobów rozwiązania jest MASA - by_ikar podał fajne - tylko po co tworzyć takie dziwne "smoki" i "potwory" jak można użyć takich wzorców jak rejestr albo zbudować własny rejestr w połączeniu z ACL... (choć i to dla mnie już przesada)...

Autor - jak możesz - uzasadnij - czemu akurat tak? Czy może to taki zamysł po prostu? (IMG:style_emoticons/default/tongue.gif)
Go to the top of the page
+Quote Post
adbacz
post
Post #13





Grupa: Zarejestrowani
Postów: 532
Pomógł: 24
Dołączył: 15.04.2011
Skąd: Kalisz

Ostrzeżenie: (0%)
-----


Ma to być prosta klasa, która będzie czymś na zasadzie pamięci podręcznej ustawień w systemie. Teraz mam wszystko podzielone ładnie na pliki, które są w różnych formatach i w różnych miejscach, ale chciałbym to przyśpieszyć. Wrzucę wszystko do pliku w formacie PHP w formie tablicy i będę tym zarządzał za pomocą klasy. Oczywiście "wrzucę" nie ręcznie, tylko skryptem, w tedy gdy dany plik konfiguracyjny został odświeżony lub gdy jeszcze nie został dodany do globalnego. Chodzi mi po prostu o przyśpieszenie operacji na ustawieniach aplikacji.



EDIT.

Różnica pomiędzy moim pomysłem z funkcją anonimową a pomysłem @by_ikar jest rzędu ok 0.02 sekundy, na 1000 wywołań.

Wywołanie moje:
  1. $result = $config->get('kernel.framework.session');

Wywołanie @by_ikar:
  1. $result = $config->get('kernel')->get('framework')->get('session');


Zaletą tego pierwszego jest to, że nawet gdy podam jako argument 'kernel.framework', to zwróci mi to tablicę jeśli ona tam jest, a w drugim przypadku zwróci mi obiekt. Musiałbym zastosować dodatkowy drugi argument funkcji, w którym definiowałbym, czy metoda get() ma zwrócić mi obiekt czy samą tablicę (w tym przypadku).

Pytanie, czy przy 1000 wywołań, narzut na poziomie 0.02 sekundy jest możliwy do zaakceptowania? Biorąc pod uwagę to, że troszke lepiej można operować na zwróconych danych.

Ten post edytował adbacz 13.07.2014, 09:31:42
Go to the top of the page
+Quote Post
Pyton_000
post
Post #14





Grupa: Zarejestrowani
Postów: 8 068
Pomógł: 1414
Dołączył: 26.10.2005

Ostrzeżenie: (0%)
-----


Nie przejmowałbym się tym.
Co do rozwiązania @by_ikar możesz dodać metodę np. toArray którą wywołasz na końcu łańcucha i gotowe.
Go to the top of the page
+Quote Post
adbacz
post
Post #15





Grupa: Zarejestrowani
Postów: 532
Pomógł: 24
Dołączył: 15.04.2011
Skąd: Kalisz

Ostrzeżenie: (0%)
-----


Mógłbym, ale co jeśli zwrócona wartość będzie stringiem zamiast obiektem? Wydaje mi się, że drugi parametr, opcjonalny, będzie lepszym wyjściem.
Go to the top of the page
+Quote Post
Pyton_000
post
Post #16





Grupa: Zarejestrowani
Postów: 8 068
Pomógł: 1414
Dołączył: 26.10.2005

Ostrzeżenie: (0%)
-----


Może być czymkolwiek. Po prostu w metodzie robisz sprawdzanie, czary mary i wypluwasz to co chcesz aby było wyplute.
Go to the top of the page
+Quote Post
Crozin
post
Post #17





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Kilka rozwiązań:

1. Zacznij od wczytania wielowymiarowej, zwykłej tablicy. Pozwól każdemu z modułów odpowiednio ją przetworzyć (niech każdy z modułów we własnym zakresie martwi się o strukturę danych) po czym spłaszcz całą tablicę wielowymiarową do tablicy jednowymiarowej.
2. Utwórz zestaw odpowiednich klas, których obiekty będą służyć za konfigurację. Innymi słowy pozbądź się kompletnie tablic.
3. Skorzystaj ze wspomnianego już wcześniej przeze mnie komponentu PropertyAccess z Syfmony - o ile wydajnościowo jest akceptowalny.

Napisz też dokładnie jakie problemy/trudności sprawia wykorzystanie "czystej" tablicy. Tzn. w jakim celu koniecznie chcesz posiadać metody ::get() i ::set() - może cały problem w ogóle nie jest warty zachodu?
Go to the top of the page
+Quote Post
adbacz
post
Post #18





Grupa: Zarejestrowani
Postów: 532
Pomógł: 24
Dołączył: 15.04.2011
Skąd: Kalisz

Ostrzeżenie: (0%)
-----


Jak już pisałem wczesniej. Aplikacja używa kilku plików konfiguracyjnych, które są w różnych miejscach i zapisane różnych typem (PHP, INI). Chcę przerobić to na tablicę PHP i zapisać do pamięci podręcznej do jednego pliku by zaoszczędzić troszkę czasu wykonywania skryptu. Części aplikacji odpowiedzialne za np. bazę danych czy routing, pobierały by ustawienia za pomocą tej właśnie klasy, a ona pobierała by te dane z pliku w pamięci podręcznej i odświeżała w miare zmian w plikach oryginalnych.

Wiem, że to może troszkę nie tak jak powinno być, ale jeśli jest na to inne rozwiązanie to chętnie o tym przeczytam.
Go to the top of the page
+Quote Post
Pyton_000
post
Post #19





Grupa: Zarejestrowani
Postów: 8 068
Pomógł: 1414
Dołączył: 26.10.2005

Ostrzeżenie: (0%)
-----


Tak,ujednolicić pliki konfiguracyjne
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 23.08.2025 - 04:33