squid
4.07.2005, 10:40:23
Szukam sposobu na konfiguracje frameworka. stwierdzilem ze konfiguracji moze byc tak duzo ze sesnownie byloby wykorzystac plik xml to trzymania konfiguracji.
Tu meczy mnie kilka watpliwosci, ktroe mam nadzieje pomozecie mi rozwiac.
Jak czytac plik konfiguracyjny XML. Waham sie miedzy PEAR::Config a SimpleXML z php5 a mmoze warto siegnac po inne rozwiazanie.
Druga sprawa to wydajnosc. Oczywiscie szkoda by bylo zeby kazde wywolanie strony wizalo sie z przetworzeniem XML'a wiec wymyslilem sobie ze sprasuje plik tylko przy pierwszym ladowniau i umieszcze go w tablicy $_SESSION albo stworze obiekt do ktorego wrzuce konfiguracje i umieszcze calosc w zmiennej sesji.
Powiedzcie mi czy moje myslenie idzie w dobrym kierunku i jak Wy to robicie.
Bede tez wdzieczny za linki
nospor
4.07.2005, 10:44:40
Co do wydajności. Przy pierwszym wczytaniu xml załaduj go do cache. Sesja będzie trzymala xml tylko dla danego gościa. Kolejny gostek bedzie musial znowu wczytywac xml. Cache będzie dzialal dla każdego. W przypadku zmiany konfiguracji wystarczy tylko cache usunąć.
Jest parę bibliotek do cache - poszukaj
squid
4.07.2005, 10:49:07
Cytat(nospor @ 2005-07-04 11:44:40)
Co do wydajności. Przy pierwszym wczytaniu xml załaduj go do cache. Sesja będzie trzymala xml tylko dla danego gościa. Kolejny gostek bedzie musial znowu wczytywac xml. Cache będzie dzialal dla każdego. W przypadku zmiany konfiguracji wystarczy tylko cache usunąć.
No ale cache tez gdzies trzeba zapisac i pewnie na dysku wiec i tak bede mial odczyt z dysku co zajmuje chwile tyle ze wydaje mi sie postac bedzie inna np. tablica php a skoro tak to moze wogole lepiej trzymac konfiguracje w tablicy i tak ja stworzyc na poczatku?
heh - ale pamietaj o 2 rzeczach.
1. Sesja również jest trzymana na dysku - w serializowanej tablicy, któa jest ładowana do pamięci w trakcie uruchamiania skrytpu.
Twoje cache może byc ładowane w identyczny sposób.
2. możesz podzielić konfiguracje na grupy, i ładować odpowiednie tylko w razie potrzeb - co jeszcze bardziej podniesie wydajność cache.
nospor
4.07.2005, 10:57:39
Cytat
odczyt z dysku co zajmuje chwile tyle
Odczyt zawartości pliku jest i tak o wiele szybszy niż odczyt i parsowanie pliku xml
squid
4.07.2005, 11:04:57
Cytat(DeyV @ 2005-07-04 11:54:33)
1. Sesja również jest trzymana na dysku - w serializowanej tablicy, któa jest ładowana do pamięci w trakcie uruchamiania skrytpu.
Twoje cache może byc ładowane w identyczny sposób.
2. możesz podzielić konfiguracje na grupy, i ładować odpowiednie tylko w razie potrzeb - co jeszcze bardziej podniesie wydajność cache.
ad. 1 - jestem tego swiadom. wiec moze skrypt powinien sprawdzac czy istnieje plik z serializowana konfiguracja jesli tak to go czyta jesli nie to przetwarza XML i zapisuje taki plik. Do serializacji uzylbym po prostu f-cji serialize.
A wracajac do sesji jesli zamisat zwyklego pliku uzylbym bazy danych do przechowywania sesji to dla duzej konfiguracji moglbym osiagnac jakies zyski czasowe?
ad. 2
no powiedzmy ze podziele sobie konfigurace ja czesci:
a) baza danych

istniejace w systemie modele (kozystam z MVC)
c) dopuszczalne wartosci dla tablic POST i GET
d) dane dodatkowe dla konkretnego modelu
nic wiecej na razie nie trzymam w konfiguracji wiec przy takim podziale punkty a-c laduje zawsze bo sa niezbede do odslugi zapytania i d zalaczam dopiero gdy odnaleziono model. Ale dochodza mi tu dodatkowe operacje odczytu w koncu zawsze jakis podel jest wywolywany wiec w takim przypadku odczytuje 2 pliki i jeszcze musze sprawdzic czy istnieja a to kolejne dwa ruchy glowicy. Moze otwieranie jednego duzego pliku z cala konfiguracja trwa nieco mnie? chyba to przetestuje
Cytat
A wracajac do sesji jesli zamisat zwyklego pliku uzylbym bazy danych do przechowywania sesji to dla duzej konfiguracji moglbym osiagnac jakies zyski czasowe?
Nie będzie takowych - odczyt z dysku jest szybszy niż zapytania do bazy.
Cytat
a) baza danych
istniejace w systemie modele (kozystam z MVC)
c) dopuszczalne wartosci dla tablic POST i GET
d) dane dodatkowe dla konkretnego modelu
To wszystko można zcache'wac - pozatym podpunkt

- nie lepiej to dopisać do konfigu jakieś tam akcji i każda miała by przyporządkowane potrzebne jej zmienne :?:
squid
4.07.2005, 13:16:12
Zrobilem sobie przykladowy kod ale cos "dserializowanie" mi nie dziala, oto kod:
<?php
class configuration
{
public function __construct ()
{
$cacheFile = './cache/configuration.ctmp';
{
}
else
{
$this->conf = simplexml_load_file('./xml/configuration.xml');
file_put_contents
( $cacheFile, serialize ( $this->conf ) ); }
return true;
}
}
?>
a wywoluje to w innym pliku:
<?
require ( './class/configuration.class.php' );
$c = new configuration();
?>
no ale po odczycie pliku cache i uzyciu unserialize ciagle dane sa zserializowane. Cos przeoczylem??
nospor
4.07.2005, 13:24:35
readfile wyrzuca ci plik na wyjscie a zwraca liczbe a nie zawartosc pliku. uzyj file_get_contents.
pozatym sprawdz czy ci wogole w chodzi w czytanie cache:
<?php
class configuration
{
public function __construct ()
{
$cacheFile = './cache/configuration.ctmp';
{
}
else
{
$this->conf = simplexml_load_file('./xml/configuration.xml');
file_put_contents
( $cacheFile, serialize ( $this->conf ) ); }
return true;
}
}
?>
squid
4.07.2005, 13:33:59
Cytat(nospor @ 2005-07-04 14:24:35)
readfile wyrzuca ci plik na wyjscie a zwraca liczbe a nie zawartosc pliku. uzyj file_get_contents.
pozatym sprawdz czy ci wogole w chodzi w czytanie cache:
o tym zapomnialem

teraz mam tak:
<?php
class configuration
{
public function __construct ()
{
$cacheFile = './cache/configuration.ctmp';
{
}
else
{
$tmp = simplexml_load_file('./xml/configuration.xml');
$this->conf = $tmp;
file_put_contents
( $cacheFile, serialize ( $this->conf ) ); }
return true;
}
}
?>
czyta mi ladnie i zapisuje ale unserialize zwraca blad:
Warning: unserialize() [function.unserialize]: Node no longer exists in configuration.class.php on line 13
to samo dla lini 14
nospor
4.07.2005, 13:39:43
będę strzelal, gdyż nigdy nie uzywalme simplexml_load_file. Ty chyba serializujesz referencje do obiektów (nodów), które przy wczytywaniu z cache poprostu nie istnieją, czyli ze serialize dzialalo na referencjach a nie obiektach
squid
4.07.2005, 13:52:41
Cytat(nospor @ 2005-07-04 14:39:43)
będę strzelal, gdyż nigdy nie uzywalme simplexml_load_file. Ty chyba serializujesz referencje do obiektów (nodów), które przy wczytywaniu z cache poprostu nie istnieją, czyli ze serialize dzialalo na referencjach a nie obiektach
nie jestem pewien czy dobrze Cie rozumiem ale oto wartosc wczytana z cache:
Cytat
O:16:"SimpleXMLElement":3:{s:4:"lang";O:16:"SimpleXMLElement":1:{s:7:"default";s:2:"pl";}s:5:"ldata";a:2:{i:0;O:16:"SimpleXMLElement":3:{s:2:"id";s:2:"pl";s:6:"coding";s:10:"ISO 8859-2";s:4:"name";s:6:"Polski";}i:1;O:16:"SimpleXMLElement":3:{s:2:"id";s:2:"en";s:6:"coding";s:10:"ISO 8859-1";s:4:"name";s:7:"English";}}s:2:"db";O:16:"SimpleXMLElement":5:{s:2:"db";s:5:"mysql";s:4:"host";s:9:"localhost";s:5:"login";s:4:"user";s:4:"pass";s:4:"pass";s:8:"database";s:4:"data";}}
poza tym w manualu:
Cytat
object simplexml_load_file ( string filename [, string class_name [, int options]] )
i na stronie
http://zend.com/php5/articles/php5-simplexml.php :
Cytat
With SimpleXML, element names are automatically mapped to properties on an object, and this happens recursively.
wiec wyglada to na obiekty wg mnie
EDIT:
napisalem podobna klase dla sesji:
<?php
class configuration2
{
//public $conf = array ();
public function __construct ()
{
$cacheFile = './cache/configuration.ctmp';
if ( isset ( $_SESSION['configuration'] ) ) {
var_dump ( $_SESSION['configuration'] ); }
else
{
$_SESSION['configuration'] =
simplexml_load_file('./xml/configuration.xml');
var_dump ( $_SESSION['configuration'] ); }
return true;
}
}
?>
plik test.php:
<?
require ( './class/configuration2.class.php' );
$c = new configuration2();
//var_dump ( $c->conf );
var_dump ( $_SESSION['configuration'] );
?>
i o dziwo tez mam problemy:
Cytat
Warning: session_start() [function.session-start]: Node no longer exists in test.php on line 5
Warning: var_dump() [function.var-dump]: Node no longer exists in class\configuration2.class.php on line 11
object(SimpleXMLElement)#1 (0) { }
sprawdzilem dla innych aplikacji ktore wczesniej dzialaly i przy wywolaniu session_start() jest tez ten problem, wyglada wiec na to ze to serwer zawodzi, zrestartowalem i nic, ktos ma pomysl jak emu zaradzic?
Uzywam php 5.0.3
Eh, znany błąd, nie można serializować obiektów simplexml. Najpierw sobie to do tablicy przekonwertuj.
squid
4.07.2005, 15:49:13
Cytat(bela_666 @ 2005-07-04 16:47:11)
Eh, znany błąd, nie można serializować obiektów simplexml. Najpierw sobie to do tablicy przekonwertuj.
przegladalem changelog'a do 5.0.4 i zalatano tam kilka dziur odnosnie simpleXML ale czy zalatano i ten? bo ja niezauwazylem ale moze czytac nie umiem

EDIT: a jak dokonac takiej konwersji z obiektu do tablicy??
Przenosze.
php pro -> PHP5
czemu, chyba nie musze tlumaczyc.
Cytat(squid @ 2005-07-04 16:49:13)
Cytat(bela_666 @ 2005-07-04 16:47:11)
Eh, znany błąd, nie można serializować obiektów simplexml. Najpierw sobie to do tablicy przekonwertuj.
przegladalem changelog'a do 5.0.4 i zalatano tam kilka dziur odnosnie simpleXML ale czy zalatano i ten? bo ja niezauwazylem ale moze czytac nie umiem

EDIT: a jak dokonac takiej konwersji z obiektu do tablicy??
Albo jakąś funkcją simplexml2array albo, co ja preferuje, wszystko po kolei parsujemy w foreach
squid
4.07.2005, 16:46:41
probowalem z foreachami ale tak latwo sie nie dalo, ostatecznie uzylem f-cji z manuala i wyglada to tak:
<?php
class configuration2
{
public function __construct ()
{
$cacheFile = './cache/configuration.ctmp';
if ( isset ( $_SESSION['configuration'] ) ) {
var_dump ( $_SESSION['configuration'] ); }
else
{
$conf = simplexml_load_file('./xml/configuration.xml');
//$tmp = array_values($conf);
$_SESSION['configuration'] = $this->simplexml2array ( $conf );
var_dump ( $_SESSION['configuration'] ); }
return true;
}
private function simplexml2array($xml)
{
if (get_class($xml) == 'SimpleXMLElement')
{
$attributes = $xml->attributes();
foreach($attributes as $k=>$v)
{
if ($v) $a[$k] = (string) $v;
}
$x = $xml;
$xml = get_object_vars($xml);
}
{
{
return (string) $x; // for CDATA
}
foreach($xml as $key=>$value)
{
$r[$key] = $this->simplexml2array($value);
}
{
$r['@'] = $a; // Attributes
}
return $r;
}
return (string) $xml;
}
}
?>
Całe to parsowanie XML do zserializowanej tablicy/obiektu simplexml/whatever ma na celu zwiększenie wydajności, więc simplexml2array jest IMHO błędnym rozwiązaniem.
Bo dostajesz dosyć skomplikowaną tablicę, odzwierciedlającą jakoś tam strukturę XMLa. A przecież nie potrzebujesz
tablicy. Potrzebujesz obiektów skonfigurowanych za pomocą tej tablicy. Sama tablica nic nie robi. Szybciej jest zserializować gotowe do użycia obiekty, niż tworzyć je od nowa na podstawie tej tablicy za każdym razem.
Nie żebym się chwalił, ale patrz phiend2

.
@hawk - załóżmy, że ten config się zmienia bądź jest zależny od jakimś parametrów - np. z konfiga o stopień wyżej - tablica się zmieni a ty znowu będziesz cache'ował kilka czy kilkanaście obiektów :?:
A czemu nie? Jaka jest różnica (w sensie wydajności) pomiędzy parsowaniem XMLa do tablicy, a parsowaniem XMLa do skonfigurowanych obiektów?
Poza tym, nie wyobrażam sobie, żeby w środowisku produkcyjnym konfiguracja się co chwilę zmieniała...
Cytat
Poza tym, nie wyobrażam sobie, żeby w środowisku produkcyjnym konfiguracja się co chwilę zmieniała...
Chodzi mi bardziej oto iż konfiguracja czegoś tam

może być tworzona dynamicznie na podstawie dostarczonych danych.
Ale nie oto chodzi - z twojego poprzedniego posta wywniskowałem, że tworzysz różne obiekty potrzebne do wykonania jakieś akcji - natomiast ty mówiłeś o obiekcie konfigu - my bad
Nie, nie, tworzę obiekty. Intercepting Filter. Jak mam parsować XML do tablicy, zapisywać tablicę, potem tworzyć te filtry, które na podstawie zawartości tablicy coś tam zrobią, to wolę zapisać do pliku gotowy do użycia filtr.
A jeżeli konfiguracja czegoś tam ma być tworzona dynamicznie, to i tak nie będziemy zapisywać tego w XML, prawda? Chociaż nie przychodzi mi do głowy zastosowanie tego.
Nievinny
5.07.2005, 11:24:35
To może powiedzmy co to konfiguracja? Bo, według mnie to podstawowe i naprawdę podstawowe dane dotyczące uruchomienia systemu, np informacje o tabeli, użytkownik i haśle w DB, domena i domyślna akcja. Tyle wystarczy, więc popierwam @hawka bo zamiast komplikować sobie życie i kod wczytujesz XML do obiektów i masz gotowe do uzycia obiekty, które cachujesz, potem tylko sprawdzasz czy konfig nie uległmodyfikacji (np za pomocą checksumy).
serafin
10.07.2005, 23:16:31
Jedyne co mi sie nasuwa - lol, rotfl, omg!
Przeciez XML jest po to by ulatwic komus z "zewnatrz" edycje konfigow, prawda?
Wiec zalozmy ze plik xml jest forma pierwotna, ktora nastepnie transformujemy do tablicy php, cachuj'emy i korzystamy z tablicy a nie z user-readable XML.
Wiec imho simplexml2array to bardzo dobry pomysl, o ile zawsze korzystac bedziemy z tablicy php a nie obiektow SimpleXML.
Takie moje zdanie (btw. korzystanie z obiektow wiaze sie z pewnym narzutem czasowym, wiec skoro mozna korzystac z o niebo szybszej tablicy to czemu nie?)
squid
11.07.2005, 08:55:37
@ hawk - szczerze mowiac jeszcze nie rozgryzlem zrodelek phiend2 ale pomysly sa calkiem intrygujace

@ Nievinny - taka konfiguracja o jakiej ty mowisz moze sie zawrzec w kilku stalych ja potrzebuje znacznie potezniejszego narzedzia, trzymam w konfiguracji wszystkie akcje i modele zeby controler przed wywolaniem sprawdzil czy takie cos intnieje, trzymam oczekiwane wartosci wszystkich danych post i get zeby moc je zweryfikowac, trzymam cala mase innych konfiguracyjnych rzeczy jak pomyslne sortowanie, ile ma. moze byc sztuk jednego towaru w koszyku i wiele takich drobiazgow.
Nie wiem czy dobrze rozumiem ale zalozmy ze mam taka klase
<?php
class basket
{
// ogolnie jest to koszyk z zakupami
...
public $maxQuantity;
...
}
?>
I powiedzmy ze wlasciwosc $maxQuantity chcem ustawic z konfiguracji, moze controler podczas wywyolania zapytania skro jest w stanie stwierdzic jakie obiekty beda potrzebne tworzy je ustawiajac odpowiednie wlasciwosci z konfiguracji nastepnie serializuje i zapisuje w pliku tak zeby nastepne wywolanie nie wiazalo sie z czytaniem XML i zeby dla nastepnego uzytkownika czy wywolania konfiguracja nie byla czytana. Po prostu zczytujemy serializowana skonfigurowana klase.
Herezje?
Nievinny
11.07.2005, 12:57:52
Herezje? -> niekoniecznie; To jest możliwe, ale jeżeli właściwość jest publiczna to załamanie oop (ale o tym nie będe psioczył). W każdym razie jaki jest sesn powiedzmy trzymania 30 klas w postaci zserializowanej i wczytywanie inaczej niż z bazowych plików? Nie będą one już potrzebne? Jeżeli konfiguracja zmienia się powiedzmy raz na miesiąc i masz uruchomiony tokenizer to można zrobić ustawienie wartości do stałych klasy (const) jako wartości i wczytywanie z pliku klasy. Jezeli nie to zrobić 1-2 klasy konfiguracyjne konfigurujące inne klasy.
squid
11.07.2005, 21:29:37
Cytat(Nievinny @ 2005-07-11 13:57:52)
Herezje? -> niekoniecznie; To jest możliwe, ale jeżeli właściwość jest publiczna to załamanie oop (ale o tym nie będe psioczył). W każdym razie jaki jest sesn powiedzmy trzymania 30 klas w postaci zserializowanej i wczytywanie inaczej niż z bazowych plików? Nie będą one już potrzebne? Jeżeli konfiguracja zmienia się powiedzmy raz na miesiąc i masz uruchomiony tokenizer to można zrobić ustawienie wartości do stałych klasy (const) jako wartości i wczytywanie z pliku klasy. Jezeli nie to zrobić 1-2 klasy konfiguracyjne konfigurujące inne klasy.
Jezeli chodzi o publiczne wlasciwosci to byl tylko przyklad ale przeciez tez sie przydaja.
A taka klasa konfiguracyjna jak wg Ciebie mialaby dzialac?
Vengeance
11.07.2005, 23:16:38
Ja robie to tak, iż za każdym razem wczytuje XML poprzez SimpleXML (jak ktoś chce to cache dorobić nie problem) i mam podstawowe metody do wyciągania danych: Config->GetParam(<xml-path>)
Potem, już w ciele aplikacji, np. podczas tworzenia obiektu Basket
wywołuje Basket->SetMaxQuantity(Config->GetParam('/app/basket/maxQuantity'));
DaNTe
15.07.2005, 13:36:18
A może ktoś mi powie jak sensownie wyszukiwać po takim XMLu:
<team>
<name>Diggers</name>
<members>
<member>Adrea</member>
<member>Joe</member>
</members>
<tool>hammer</tool>
<tool>nail</tool>
</team>
<team>
<name>Miners</name>
<members>
<member>Koel</member>
</members>
<tool>Lamp</tool>
</team>
I teraz interesuje mnie czy Joe pracuje jako Digger i jesli tak to jakich potrzebuje narzędzi.
Mnie do glowy przychodzą jedynie nieelastyczne partyzanki w stylu zmiany na tablice asocjacyjne (Miners=>Joe=>tool('hammer'.'nail'))
Bo foreachem z breakem tez za cholere nie wiem jak sie po tym poruszac
serafin
15.07.2005, 13:49:34
Ja uzywam DomXML z php5
hawk
15.07.2005, 20:01:41
@dante: Jak wyszukiwać? Najprościej xpath. Jak chcesz tylko wyszukiwać po XMLu, to nie zamieniaj go na tablice/obiekty.
squid
20.07.2005, 10:12:36
Cytat(hawk @ 2005-07-15 21:01:41)
@dante: Jak wyszukiwać? Najprościej xpath. Jak chcesz tylko wyszukiwać po XMLu, to nie zamieniaj go na tablice/obiekty.
ale jak go nie zamienie na tablice to bede musal za kazdym razem kiedy wywoluje skrypt czytac xml'a. Poniewaz obiektu simpleXML nie da sie zserializowac to mozna zamienic go tylko na tablice (albo inny obiekt) ale jak juz mowilismy jest to spory narzut czasowy.
A mozna powiedzmy caly plik zczytac do zmiennej i zserializowac ja i potem ew. chodzic xPath po tym pliku zmiennek? czy taie rozwiazanie jest dobre?
Vengeance
20.07.2005, 12:22:28
A moze zrezygnowac z XML na rzecz kilku .ini ? ;p
Ociu
20.07.2005, 12:33:46
Ja zaczynam zabawe w mvc i mape pierwotnie miałem w xml, potem przeszła do pliku ini, aż w koncu zatrzymało się na talbicy pliku autoloadera :-)
Vengeance
22.07.2005, 02:06:45
To tak jakby cofnołeś się w rozwoju

Zazwyczaj wszyscy idą ścieżką php>txt>xml
squid
3.08.2005, 12:46:19
Pogubilem sie troche w roznych rozwiazaniach. Mam sobie jakis tam obiekt ktory czyta dwolny format pliku konfiguracyjnego po czym, no wlasnie co zrobic po zczytaniu takiego pliku.
1. Stworzyc tablice ze zmiennymi konfiguracyjnymi i serializowac ja miedzy wywolaniami?
2. Stworzyc obiekt ktory bedzie przetrzymywal cala konfiguracje we wlasciwosciach i udostepnial je przy pomocy metody/metod
3. Stworzyc obiekt ktory podczas wywolania akc ji bedzie ja konfigurowal np. tak ze przez okreslopna metoda w akcji ustawi jej wlasciwosci wykorzystywanie podczas pracy tej akcji
4. Jeszcze cos innego?
POMOCY!
Vengeance: zawsze się wyróżniałem...

A co do wyboru, to wróciłem to pliku ini
squid
8.08.2005, 11:26:57
Cytat(Ociu @ 2005-08-04 12:57:38)
Vengeance: zawsze się wyróżniałem...

A co do wyboru, to wróciłem to pliku ini

wasze prywatne potyczki bardzo mi pomagaja w rozwiazaniu problemu ;p
Vengeance
8.08.2005, 12:30:11
@squid: Po pierwsze, jakie potyczki? Po drugie nie tylko twoje problemy są na forum... skoro nie otrzymałeś odpowiedzi to przypominanie się wiele nie da.
squid
8.08.2005, 17:15:36
Cytat(Vengeance @ 2005-08-08 13:30:11)
@squid: Po pierwsze, jakie potyczki? Po drugie nie tylko twoje problemy są na forum... skoro nie otrzymałeś odpowiedzi to przypominanie się wiele nie da.
inaczej to odbieram i nie oczekuje ze wszyscy zechca cos tu mi napisa bo ja chce ale skoro juz to wyjasnilismy to zrobilem test simpleXML kontra DOM.
Wiadomo obiektu simpleXML nie da sie zserializowac wiec trzeba go zamienic na tablice i poznie ew. obiekt. W moim przykladzie zamieniam na tablice.
Hawk twierdzi ze zabawa w zamieniania simpleXML na cokolwiek jest zbyt kosztowna.
oto plik testowy:
<?php
require_once 'Benchmark/Iterate.php';
$benchmark = new Benchmark_Iterate;
$file = "./xml/test.xml";
function simple_xml ($file)
{
$xmlObject = simplexml_load_file ( $file );
$xmlArray = simplexml2array ($xmlObject);
}
function simplexml2array($xml)
{
if (get_class($xml) == 'SimpleXMLElement')
{
$attributes = $xml->attributes();
foreach($attributes as $k=>$v)
{
if ($v) $a[$k] = (string) $v;
}
$x = $xml;
$xml = get_object_vars($xml);
}
{
// - poprawione - //
{
{
return $a;
}
return (string) $x;
}
// - koniec poprawki - //
foreach($xml as $key=>$value)
{
$r[$key] = simplexml2array($value);
}
{
$r['@'] = $a; // Attributes
}
return $r;
}
return (string) $xml;
}
$benchmark->run(1000, 'simple_xml', $file);
$result = $benchmark->get();
//var_dump ( $result );
unset ($result['iterations']);
function DOM ( $file )
{
$dom = new DOMDocument('1.0', 'iso-8859-1');
$dom->load($file);
}
$benchmark->run(1000, 'DOM', $file);
$result = $benchmark->get();
unset ($result['iterations']); ?>
na moim sprzecie odczytanie i zamana obiektu simpleXML na tablice zajmuje ok 0.65s a zabawa z DOM ok 1s. Wszytko to dla 1000 wywolan. Jaki wplyw na wynik ma sama zamiana simpleXML na tablice mozna zobaczyc komentujac linie:
<?php
$xmlArray = simplexml2array ($xmlObject);
?>
w pierwszej f-cji
Nie jestem sepem od DOM'a ale jest jeden jako rozszerzenie i jeden wbudowany w jadro (tego uzylem), moze wiecie jaka jest roznica? jesli nie ma zbyt wielkiej to moze w phiend2 trzeba zamienic DOM na cos innego?
To wszytko dla przykladowego pliku:
<?xml version="1.0" encoding="utf-8" ?>
<rss version="0.91">
<channel>
<title>What's For Dinner</title>
<link>http://menu.example.com/</link>
<description>These are your choices of what to eat tonight.</description>
<item>
<title>Braised Sea Cucumber</title>
<link>http://menu.example.com/dishes.php?dish=cuke</link>
<description>Gentle flavors of the sea that nourish and refresh you.</description>
</item>
<item>
<title>Baked Giblets with Salt</title>
<link>http://menu.example.com/dishes.php?dish=giblets</link>
<description>Rich giblet flavor infused with salt and spice.</description>
</item>
<item>
<title>Abalone with Marrow and Duck Feet</title>
<link>http://menu.example.com/dishes.php?dish=abalone</link>
<description>There's no mistaking the special pleasure of abalone.</description>
</item>
</channel>
</rss>
Vengeance
8.08.2005, 17:28:22
squid: istniejące funkcje xml2array nie pozwalają na używanie wielu możlwiości XML jak np argumenty.
Dla mnie też zrzucanie do arraya nie ma sensu. Już albo zrobić sobie gotowe do użycia obiekty (wygenerować odpowiednie pliki), lub pobierać przez xpath()
squid
8.08.2005, 19:46:07
Cytat(Vengeance @ 2005-08-08 18:28:22)
squid: istniejące funkcje xml2array nie pozwalają na używanie wielu możlwiości XML jak np argumenty.
Dla mnie też zrzucanie do arraya nie ma sensu. Już albo zrobić sobie gotowe do użycia obiekty (wygenerować odpowiednie pliki), lub pobierać przez xpath()
mowiac argumenty masz na imie atrybuty?? np:
<znacznik atrybut="wartosc"></znacznik>
Oczywiscie chce miec obiekt z konfiguracja tak zebym na niej mogl operowac (na poczatek tylko czytac) ale tak czy siak zeby dalej uzywac tego co odczytam z pliku to uzywajac simpleXML musze to zrzucic do jakies tablicy ktora w rzeczywistosci bedzie chroniona wlasciwosci na ktorej bedzie operowal obiekt konfiguracji.
XPATH, jeszcze za malo wiem o tej technologi ale postaram sie to przetestowac pod wzgledem wydajnosci i powiadomie Was o wynikach
dzieki za uwagi
Przede wszystkim, nie twierdzę, że zamiana simplexml na tablice jest kosztowna. Po prostu w moim przypadku przejście z xml bezpośrednio na obiekty było krótsze (w znaczeniu linii kodu). A i już po zapisaniu wyniku np. do gotowego pliku php kod wykorzystujący obiekty jest prostszy niż kod pakujący tablice do obiektów.
Że DOM jest wolny, to wiadomo. To cena, którą się płaci za możliwość dowolnej edycji struktury XMLa. Ale ile razy będzie parsowany taki XML? Jeżeli to konfiguracja frameworka, to naprawdę bardzo rzadko, więc nie ma to znaczenia.
A ja się ostatnio zastanawiałem nad inną rzeczą. Czy da się uwolnić od ograniczenia, że dane wejściowe są w XML? Mamy jeszcze .ini, YAML, M3, php

... Gdyby był format pośredni, to można tylko wymieniać "driver". Tylko że formatem pośrednim znowu byłyby tablice

. A tablice do XML kiepsko pasują. Przykład:
<items>
<item>foo</item>
<item>bar</item>
</items>
Tak na oko, chciałbym w wyniku mieć:
<?php
'foo',
'bar',
);
?>
... a nie ...
<?php
'foo',
'bar',
),
);
?>
Chyba że ja za bardzo kombinuję...
squid
9.08.2005, 16:36:19
DOM jest dobry ale to kombajn, czy trzeba zapuszczac kombajn do jednego klosa?
DOM daje duzo mozliwosci jest dopracowany bo w php juz istnieje jakis czas ale zajmuje duzo pamieci i nei ejst najszybszy.
Jest tez SAX ale nie za bardzo mi odpowiada, trzeba pisac jakies handlery itp.
SimpleXML bylby idealny gdyby nie to ze jest dosc niedopracowany. Wspomniany blad z serializacja sprawia ze trzeba kombinowac.
Mimo wszystko wole simpleXML bo do czytania konfiguracji powinien wystarczyc i nawet jakbym z panelu admina chcial cos napisac do pliku z configiem to tez moge.
Mialem porownac bardziej realistycznie wydajnosc SimpleXML i DOM i nawet Xpath ale sie nie da przynajmniej takim nakladem pracy jakim moge dysponowac.
To jest taki szkic klasy uzywajacej SimpleXML:
<?php
class Configuration
{
protected
$configuration = array (); protected $cachedConfigurationFile = './cache/configuration.ctmp';
public function __construct ()
{
if ( isset ( $_SESSION['configuration'] ) ) {
$this->configuration = $_SESSION['configuration'];
}
else if ( file_exists ( $this->cachedConfigurationFile ) ) {
$this->configuration = unserialize ( $cachedConfigurationString ); $_SESSION['configuration'] = $this->configuration;
}
else
{
$simpleXmlObject = simplexml_load_file('./xml/test.xml');
$this->configuration = $this->simplexml2array ( $simpleXmlObject );
file_put_contents
( $this->cachedConfigurationFile, serialize ( $this->configuration ) ); $_SESSION['configuration'] = $this->configuration;
}
return true;
}
public function getConfiguration ( $node )
{
return $this->configuration[$node];
}
protected function simplexml2array ( $xml )
{
if (get_class($xml) == 'SimpleXMLElement')
{
$attributes = $xml->attributes();
foreach($attributes as $k=>$v)
{
if ($v) $a[$k] = (string) $v;
}
$x = $xml;
$xml = get_object_vars($xml);
}
{
// - poprawione - //
{
{
return $a;
}
return (string) $x;
}
// - koniec poprawki - //
foreach($xml as $key=>$value)
{
$r[$key] = $this->simplexml2array($value);
}
{
$r['@'] = $a; // Attributes
}
return $r;
}
return (string) $xml;
}
}
?>
Zasadnicza wada jest to ze ciezko przez metode uzyskac dostpe do dowolnego poziomu zagniezdzenia tablicy dlatego na razie mozna pobrac tylko jeden z korzeni.
Macie jakis pomysl co z tym zrobic?
Vengeance
9.08.2005, 17:30:36
Cytat(squid @ 2005-08-08 20:46:07)
ale tak czy siak zeby dalej uzywac tego co odczytam z pliku to uzywajac simpleXML musze to zrzucic do jakies tablicy
Nie prawda. Ja w poprzedniej wersji swojego Framework robiłem po prostu:
Config::GetParam('/framework/db/user');
Gdzie GetParam() przerabial to na zapytanie xpath. zainteresuj sie nim bo na prawde pomaga. A mozna przy jego użyciu cuda robić.
Cuda - ciekawe jak z szybkością jeśli trzeba wczytywać cały dokument :?:
Vengeance
9.08.2005, 20:07:51
Już nie cuda... bo stwierdziłem że XML jest zbędny i z niego nie korzystam. W ogóle staram się pisać tak by unikać konfiguracji.
No ale kolega chciał sposobów to podałem stare :]
squid
9.08.2005, 20:45:42
@NuLL z moich testow wynika ze wszystko jest szybsze od DOM, nie testowalem zajetosci pamieci ale DOM pewnie tez zajmowalby najwiecej.
@Vengeance nie uparlem sie na XML, testuje tez inne rozwiazania ale najwiecej problemu sprawia mi wlasnie XML stad ten temat.
Pliki ini oferuja zbyt mala fukcjonalnosc, przeszkadza mi glownie brak zagniezdzen ktore z latwoscia uzyskam przez xml np:
<znacznik_1>
<znacznik_2>
<znacznik_3>bla</znacznik_3>
</znacznik_2>
<znacznik_4> bla bla </znacznik_4>
</znacznik_1>
pliki ini sa dobre do trzymania konfiguracji typu ile mam wyswietlic rekordow na stronie itp. ale gdybym chcial trzymac mape plikow lub cos bardziej skomplikowanego to sie nie sprawdzaja choc nie wykluczylem do konca plikow ini. Jesli nie bede zadowolony z obslugi XML przez php to pewnie wybiore te rozwiazanie.
Trzymanie konfiguracji w stalych jest jeszcze bardziej ograniczone.
Obecnie konfiguracje trzymam w statycznej wlasciwosci kontrolera ale malo eleganckie to jest.
Mozna trzymac tez w bazie danych, ja w ten sposob przetrzymuje mape akcji, w ten sposob latwo sprzegam to z systemem uprawnien do wykonania akcji przez uzytkownika.
ale Vengeance jesli potrafisz pisac kod nie wymagajacy konfiguracji to albo lubisz pisac wiecej kodu niz potrzeba albo jestes zaje...genialny.
matid
9.08.2005, 21:02:18
Cytat(squid @ 2005-08-09 21:45:42)
ale Vengeance esli potrafisz pisac kod nie wymagajacy konfiguracji to albo lubisz pisac wiecej kodu niz potrzeba alebo jest zaje...genialny.
Kilka algorytmów konfigurujących skrypt na podstawie działań użytkownika/administratora i jest git ;P
U mnie konfig to dość rozbudowany moduł, na razie 13 klas i do tego jeszcze kilka interface'ów. Jak na razie mam:
ConfigCache, ConfigCacheCreator, ConfigCacheGenerator, ConfigCacheLoader, ConfigCacheWriter, ConfigContainer, ConfigEntry, ConfigSection, INIConfigParser, PHPConfigParser, SerializedConfigCacheLoader, SerializedConfigCacheWriter, XMLConfigParser.
A używanie samego configu wygląda tak:
<?php
class OpenConfig
{
public static function getConfig
( String
$FilePathname ) {
if( isset( self::$aConfigArray[ $FilePathname->toString() ] ) ) {
return self::$aConfigArray[ $FilePathname->toString() ];
}
else
{
return self::loadConfig( $FilePathname );
}
}
public static function addConfig
( String
$FilePathname, ConfigContainer
$Config ) {
self::$aConfigArray[ $FilePathname->toString() ] = $Config;
}
public static function loadConfig
( String
$FilePathname ) {
{
if( !file_exists( OF_CACHE_DIR
. md5( $FilePathname->toString() ) . '.php' ) || ( filemtime( $FilePathname->toString() ) > filemtime( OF_CACHE_DIR
. md5( $FilePathname->toString() ) . '.php' ) ) ) {
$ConfigCacheGenerator = new ConfigCacheGenerator;
$FileExtension = clone $FilePathname;
$FileExtension->replace( new String( '/(.*?).([^.]+)?$/i' ), new String( '2' ) );
$FileExtension->toLowerCase();
switch( $FileExtension->toString() )
{
case 'xml':
$ConfigParser = new XMLConfigParser;
break;
case 'php':
$ConfigParser = new PHPConfigParser;
break;
case 'ini':
$ConfigParser = new INIConfigParser;
break;
}
$Config = $ConfigParser->parseFile( $FilePathname );
$ConfigCacheGenerator->setProvider( $Config );
$ConfigCacheCreator = new ConfigCacheCreator( $Config );
$ConfigCacheGenerator->setCreator( $ConfigCacheCreator );
$ConfigCacheWriter = new SerializedConfigCacheWriter
( new String
( OF_CACHE_DIR
. md5( $FilePathname->toString() ) . '.php' ) ); $ConfigCacheGenerator->setWriter( $ConfigCacheWriter );
$ConfigCacheGenerator->generateCache();
}
else
{
$ConfigCacheLoader = new SerializedConfigCacheLoader;
$Config = $ConfigCacheLoader->loadCache( new String
( OF_CACHE_DIR
. md5( $FilePathname->toString() ) . '.php' ) ); }
self::addConfig( $FilePathname, $Config );
return $Config;
}
else
{
throw new FileNotExistsException( 'Config file (' . $FilePathname->toString() . ') does not exist' );
}
}
}
?>
A to przykład pobierania danych z konfiguracji:
<?php
$ControllerConfig = OpenConfig::getConfig( new String( 'config.xml' ) )->getSection( new String( 'Controller' ) );
$ModuleName = $ControllerConfig->getEntry( new String( 'Error404Module' ) )->getValue();
$ActionName = $ControllerConfig->getEntry( new String( 'Error404Action' ) )->getValue();
?>
Na razie dość niewygodne, bo przy każdym odwołaniu do konfiguracji z innego miejsca aplikacji trzeba podać plik z jakiego się chce skorzystać, ale to tylko dla potrzeb mojego testowania (tak wygodniej mi się pisze ;P)
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.