Witaj, Gościu O nas | Kontakt | Mapa
Wortal Forum PHPEdia.pl Planeta Kubek IRC Przetestuj się!

AJAX - porządkowanie aplikacji

Wykorzystanie bibliotek

Istnieje wiele bibliotek narzędziowych mających na celu ułatwienie integracji JavaScriptu i PHP. Wszystkie uwzględniają jakąś metodę przesyłania danych, ale większość oferuje dodatkowe możliwości, od bezpośredniego odwzorowania metod klas PHP na pośrednika JavaScriptu, po środowisko tworzenia elementów interfejsu użytkownika. Przyjrzyjmy się bliżej dwóm popularnym pakietom: bibliotekom JPSpan i HTML_AJAX.

JPSpan

Najpierw zajmiemy się pakietem JPSpan - jedną z bardziej dojrzałych bibliotek AJAX dla PHP, dostępną od listopada 2004 r. Podstawową funkcją biblioteki jest niezależna od przeglądarki obsługa mechanizmu AJAX bazująca na XMLHttpRequest, z możliwością wyboru pracy synchronicznej lub asynchronicznej. Dostępne jest wspólne, obiektowe API dla JavaScriptu i PHP. JPSpan obsługuje też wiele innych funkcji, na przykład przezroczyste odwzorowania obiektów z bardzo dobrą serializacją danych, pozwalającą odwzorowywać tablice PHP na obiekty JavaScriptu.

Strona z serwera jest dołączana do wynikowych stron HTML ze znacznikiem client, generując pośrednie klasy JavaScript o takim samym API, jak klasy PHP. Ze względu na ograniczenia PHP4, wszystkie nazwy klas i metod są zapisywane małymi literami. Domyślny serwer JPSpan nosi nazwę JPSpan_Server_PostOffice i może służyć do odwzorowywania na JavaScript zarówno całych klas, jak i ich części. Korzystając z serwera w dużym serwisie można rozważyć dodanie znacznika class, co pozwoli ograniczyć liczbę klas dołączanych i rejestrowanych na serwerze, a tym samym zmniejszy koszt przetwarzania. Osobiście nie doświadczyłem jednak żadnych problemów wydajnościowych nawet przy pięciu stale zarejestrowanych klasach integracyjnych.

Wywołania polegają na utworzeniu instancji odpowiedniej klasy JavaScriptu, a następnie wywoływaniu jej metod. W chwili utworzenia instancji w trybie asynchronicznym, określana jest klasa zwrotna, po czym wyniki są przesyłane jej metodom o takich samych nazwach, jak metody pierwotnie wywoływane. JPSpan dodatkowo obsługuje złożone typy danych, w tym wielowymiarowe tablice i obiekty, jak również serializację i przekazywanie błędów PHP do JavaScriptu z możliwością konfiguracji obsługi błędów po stronie klienta.

JPSpan i PEAR

Wersja biblioteki JPSpan dla repozytorium PEAR jest dostępna w serwisie http://www.pearified.com. Do instalacji będzie potrzebny PEAR w nowej wersji 1.4, obsługujący inne kanały niż tylko http://pear.php.net. Poleceniem pear channel-discover pearified.com należy dodać kanał do repozytorium, po czym można już zainstalować JPSpan poleceniem pear install pearified/JavaScript_JPSpan.

Strona serwera

Przyjrzyjmy się działaniu JPSpan nieco bliżej na prostym przykładzie typu Hello World, wyświetlającym losowy napis w reakcji na kliknięcie i pozwalającym dodawać nowe napisy. Zaczynamy od utworzenia klasy helloworld, zawierającej proste metody PHP do obsługi dodawania napisów do tablicy sesyjnej, zwracania długości tablicy i wyświetlania losowego napisu z tablicy. Są to odpowiednio metody addString(), stringCount() i randomString(), a ich kod przedstawia Listing 1.

Praca z klasami JPSpan nie różni się niczym od obsługi zwykłych klas. Trzeba tylko pamiętać, że klasa ta jest odtwarzana przy każdym wywołaniu ze strony JavaScriptu, więc utrzymywanie danych składowych między wywołaniami wymaga pamiętania instancji klasy w ramach sesji.

Musimy jeszcze dołączyć JPSpan i odpowiedni plik serwera PostOffice, po czym możemy stworzyć nową instancję serwera i zarejestrować w niej naszą klasę wywołując $S->addHandler(new HelloWorld()). Pozostaje jeszcze tylko określić, czy chcemy wysłać kliencki kod JavaScript, czy też obsługiwać żądania. Jak widać na Listingu 1, obiektowe API JPSpan bardzo ułatwia przygotowania po stronie serwera.

Strona klienta

Teraz zajmiemy się stroną kliencką naszej prostej aplikacji – Listing 2 przedstawia kod klienta. Od razu zwraca uwagę wyraźne rozdzielenie kodu HTML i PHP podczas pracy z JPSpan. Wystarczy tylko umieścić w ramach strony HTML poniższy, automatycznie generowany kod, odpowiedzialny za faktyczne połączenie HTML i PHP:

<script type='text/javascript'
  src='jpspan_server.php?client'>
</script>
Przy odrobinie pracy nagłówkami pozwala to wygodnie obsłużyć składowanie znanych informacji po stronie klienta, co bardzo przydaje się na przykład przy dodawaniu do istniejącego serwisu pola autouzupełniania.

Następnie tworzymy klasę JavaScriptu o nazwie <b>hwCallback</b>, zawierającą metody zwrotne zastępujące treść odpowiednich elementów <b>&lt;div&gt;</b> wartościami podanymi przez serwer z wykorzystaniem właściwości <b>innerHTML</b>. Pozostaje już tylko utworzyć zdalny obiekt:
<literal class='javascript'>
var remoteHW=new helloworld(hwCallback);

Klasa helloworld jest wyeksportowaną klasą PHP, którą wcześniej utworzyliśmy po stronie serwera. Nazwa klasy zawiera wyłącznie małe litery, gdyż PHP4 nie rozróżnia wielkości liter w nazwach klas i funkcji. Reszta kodu z Listingu 2. to już tylko dodanie formularza HTML z odpowiednimi metodami obsługi - i już możemy się pobawić naszą pierwszą aplikacją stworzoną w technologii AJAX.

HTML_AJAX

HTML_AJAX a nazwy klas

Nazwy klas zwracane przez PHP4 są zawsze zapisane małymi literami. Jeśli koniecznie chcesz zachować rozróżnienie wielkości liter lub potrzebujesz zgodności między PHP4 i PHP5, musisz skorzystać z dodatkowych parametrów metody registerClass(), określających nazwę klasy rejestrowanej w JavaScripcie oraz tablicę eksportowanych metod:

$server = new HTML_AJAX_Server();
$hello = new HelloWorld();
$methods = array('foo','bar');
$server->registerClass($hello,'Example',
  $methods);

Komunikat ładowania

Uruchamiając przykłady z HTML_AJAX zauważysz, że przy każdym wywołaniu AJAX pojawia się czerwone okienko z komunikatem loading. Powiadomienie to jest automatycznie wyświetlane przez HTML_AJAX i jest po prostu warstwą o określonym identyfikatorze, tworzoną jeśli wcześniej nie istniała. Jeśli więc chcesz zmienić ten komunikat, wystarczy gdzieś w kodzie HTML umieścić na przykład taki fragment:

Wyświetlania komunikatu nie da się w obecnej wersji wyłączyć po stronie serwera, ale w przyszłych wersjach HTML_AJAX taka możliwość już będzie. Aby zapobiec wyświetlaniu komunikatu trzeba nadpisać generującą go funkcję JavaScriptu:

HTML_AJAX.onOpen = function(){
  // nic
}
Serwer

Strona HTML_AJAX działająca na serwerze jest bardzo prosta - jej działanie polega na utworzeniu instancji serwera HTML_AJAX_Server, zarejestrowaniu wszystkich eksportowanych klas (zwanych tu stubs, czyli namiastkami) i obsługiwaniu nadchodzących żądań. Istnieją trzy możliwe rodzaje żądań:

  • ?ądanie klienckie, zawierające ?client=all w ciągu zapytania. Zamiast all można też podać jedną z części składowych klienta. Obecnie obsługiwanych jest pięć części (Main, Dispatcher, HttpClient, Request i JSON), a w przyszłości zostanie dodana obsługa dodatkowych, opcjonalnych części.
  • ?ądanie generowanej namiastki, zawierające ?stub=nazwaklasy w ciągu zapytania (można też podać wartość all).
  • ?ądanie AJAX, zawierające w ciągu zapytania ?c=nazwaklasy&m=nazwametody.

Pierwsze dwa rodzaje żądań można łączyć w jednym żądaniu, lecz trzeba pamiętać, że wiąże się to z pewnym kompromisem: mniej żądań to mniej połączeń z serwerem, ale z drugiej strony generowane namiastki zmieniają się częściej od danych klienckich, co może negatywnie wpłynąć na efektywność lokalnego składowania kodu. Ostrożnie należy też korzystać z żądań stub=all, gdyż namiastka na przykład dla dziesięciu klas może już być spora. W kolejnej wersji biblioteki HTML_AJAX pojawi się możliwość podawania wielu klas w ramach jednego żądania namiastki w postaci listy rozdzielanej przecinkami, a więc stub=test,test2.

Łatwa aktualizacja treści bez AJAX-a

HTML_AJAX pozwala też korzystać z podstawowych możliwości AJAX-a wyłącznie po stronie klienckiego JavaScriptu, dzięki czemu można bardzo szybko dodać do strony proste elementy używające AJAX-a lub włączyć HTML_AJAX do istniejącego środowiska. Typowym zastosowaniem jest aktualizacja zawartości elementu HTML za pomocą treści wygenerowanej przez inną stronę PHP, co daje elastyczność ramek <iframe> bez ich wad (patrz Listing 3).

Po dołączeniu do strony niezbędnego kodu JavaScriptu można pobierać treść ze wskazanego adresu na serwerze w trybie synchronicznym za pomocą HTML_AJAX.grab(url) lub w trybie asynchronicznym za pomocą HTML_AJAX.grab(url,grabCallback), gdzie argument grabCallback wskazuje funkcję zwrotną automatycznie wywoływaną przez HTML_AJAX po pobraniu treści. Można też wywołać HTML_AJAX.replace('target',url), by zastąpić zawartość elementu o identyfikatorze podanym jako target treścią pobraną z adresu url. Ze względów bezpieczeństwa można w ten sposób pobierać treści wyłącznie z adresów na tym samym serwerze. Nie jest to jednak ograniczenie biblioteki HTML_AJAX, lecz ograniczenie przeglądarki, mające na celu zapobieganie atakom cross site scripting (XSS).

Tryb synchroniczny i asynchroniczny

Biblioteki JPSpan i HTML_AJAX obie obsługują pracę zarówno w trybie asynchronicznym (z wywołaniami zwrotnymi), jak i synchronicznym (z bezpośrednim zwracaniem wartości). Ogólnie lepiej jest stosować operacje asynchroniczne, gdyż wywołania synchroniczne mogą wstrzymywać pracę interfejsu użytkownika w oczekiwaniu na odpowiedź drugiej strony. Oczywiście niekiedy jest to zachowanie pożądane, ale przesyłając większe ilości danych trzeba wtedy zawsze pamiętać o wyświetleniu komunikatu typu proszę czekać. Wywołania synchroniczne są znacznie łatwiejsze do oprogramowania, ale mimo to lepiej oprzeć się pokusie bezkrytycznego ich stosowania. ?ądania AJAX w sieci lokalnej najczęściej trwają nie dłużej niż 50 ms, ale w przypadku przesyłania danych przez Internet czas ten najczęściej wzrasta do co najmniej 250 ms. Oznacza to, że użytkownik nie będzie w stanie skorzystać z żadnego elementu strony czy nawet przełączyć się na inną zakładkę przeglądarki przez ćwierć, a często i pół sekundy.

Listing 1. Serwer JPSpan

<?php
session_start();
// Klasa powitania
class HelloWorld {
   function HelloWorld() {
      if (!isset($_SESSION['strings'])) {
         $_SESSION['strings'] = array('Hello','World','Hello World');
      }
   }
   function addString($string) {
      $_SESSION['strings'][] = $string;
      return $this->stringCount();
   }
   function randomString() {
      $index = rand(0,count($_SESSION['strings'])-1);
      return $_SESSION['strings'][$index];
   }
   function stringCount() {
      return count($_SESSION['strings']);
   }
}
// Ustawienie stałej JPSPAN
require_once 'jpspan-0.4.3/JPSpan.php';
// Załadowanie serwera PostOffice
require_once JPSPAN . 'Server/PostOffice.php';
// Utworzenie serwera PostOffice
$S = & new JPSpan_Server_PostOffice();
// Rejestracja klasy w serwerze
$S->addHandler(new HelloWorld());
// Obsługa wyświetlania JavaScriptu po dodaniu
// ciągu ?client do URL-a serwera
if (isset($_SERVER['QUERY_STRING']) &&
   strcasecmp($_SERVER['QUERY_STRING'], 'client')==0) {
   // Wyłączenie kompresji wynikowego JavaScriptu
   // (m.in. usuwania białych znaków) z powodu 
   // problemów wydajnościowych
   define('JPSPAN_INCLUDE_COMPRESS',false);
   // Wyświetlenie klienckiego JavaScriptu
   $S->displayClient();
}else {
   // Początek faktycznej obsługi żądań
   // Dołączenie obsługi błędów
   // <span class="hilite">PHP</span> 
   // błędy, ostrzeżenia i komunikaty serializowane do JS
   require_once <span class="hilite">JPSPAN</span> . '<span class="hilite">ErrorHandler</span>.<span class="hilite">php</span>';

   // Obsługiwanie żądań
   $S->serve();
}
?>

Listing 2. Klient JPSpan

<html>
<head>
  <title>Hello World w JPSpan</title>
  <script type='text/javascript' src='jpspan_server.php?client'></script>
  <script>
  // Klasa JavaScript zawierająca metody zwrotne
   var hwCallback = {
      randomstring: function(result) {
         document.getElementById('canvas').innerHTML += '<p>'+result+'</p>';
      },
      stringcount: function(result) {
         document.getElementById('count').innerHTML = result;
      },
      addstring: function(result) {
         document.getElementById('count').innerHTML = result;
      }
   }
   // Utworzenie obiektu zdalnego. Jego nazwa jest odwzorowana małymi literami, gdyż w nazwach klas i funkcji PHP4 wielkość liter nie jest rozpoznawana. Rejestrując każdą klasę na serwerze można przywrócić rozróżnianie wielkości liter.
   var remoteHW = new helloworld(hwCallback);
   function do_addString() {
      remoteHW.addstring(document.getElementById('string').value);
        document.getElementById('string').value = '';
   }
  </script>
</head>
<body onLoad="remoteHW.stringcount()">
  <input type="button" name="check" value="Pokaż losowy napis" onclick=
    "remoteHW.randomstring(); return false;">
  <div>Liczba losowych napisów: <span id="count"></span></div>
  <div id="canvas" style="border: solid 1px black; margin: 1em; padding: 1em;"></div>
  <div>
    Podaj nowy napis:
    <input type="text" name="string" id="string" size="20">
    <input type="button" name="check" value="Dodaj nowy napis" onclick=
      "do_addString(); return false;">
  </div>
</body>
</html>

Listing 3. HTML_AJAX może posłużyć do pobierania treści z innej strony na tym samym serwerze

<html>
<head>
  <script type='text/javascript' src="server.php?client=main"></script>
  <script type='text/javascript' src="server.php?client=dispatcher"></script>
  <script type='text/javascript' src="server.php?client=HttpClient"></script>
  <script type='text/javascript' src="server.php?client=Request"></script>
  <script type='text/javascript' src="server.php?client=json"></script>
</head>
<body>
<script type="text/javascript">
  function clearTarget() {
    document.getElementById('target').innerHTML = 'clear';
  }
  // Operacja 'grab' jest najprostszym zastosowaniem HTML_AJAX, polegającym na wysłaniu żądania do strony i pobraniu wyników. Można jej używać w trybie synchronicznym lub asynchronicznym (z wywołaniem zwrotnym).
  var url = 'README';
  function grabSync() {
    document.getElementById('target').innerHTML = HTML_AJAX.grab(url);
  }
  function grabAsync() {
    HTML_AJAX.grab(url,grabCallback);
  }
  function grabCallback(result) {
    document.getElementById('target').innerHTML = result;
  }
  // Operacja 'replace' może działać albo na adresie (tak jak grab), albo na zdalnej metodzie. W tym drugim przypadku trzeba ustawić defaultServerUrl na adres eksportujący wywoływaną metodę. Obecnie replace używa wyłącznie synchronicznych wywołań AJAX - wywołania asynchroniczne mogą się pojawić w przyszłości.
  function replaceUrl() {
    HTML_AJAX.replace('target',url);
  }
</script>
<ul>
  <li><a href="javascript:clearTarget()">Czyszczenie pola docelowego</a></li>
  <li><a href="javascript:grabSync()">Przykład pobrania synchronicznego</a></li>
  <li><a href="javascript:grabAsync()">Przykład pobrania asynchronicznego </a></li>
  <li><a href="javascript:replaceUrl()">Zastąpienie zawartości treścią pobraną spod wskazanego adresu</a></li>
</ul>
<div style="white-space: pre; padding: 1em; margin: 1em; width: 600px; height:
  300px; border: solid 2px black; overflow: auto;" id="target">Pole docelowe</div>
</body>
</html>
Informacje na podobny temat:
Wasze opinie
Wszystkie opinie użytkowników: (4)
przykłady
Niedziela 31 Maj 2009 6:27:19 pm - Tomplus

Szkoda że nie ma przykładowego zastosowania tych kodów... aby zobaczyć jak powinno działać.

AJAX...
Środa 28 Luty 2007 1:47:32 pm - pawelpaciorek <brak_at_maila.pl>

może jest tępy ale przeczytałem i nie bardzo wiem o co chodzi. Jeśli to ma być dla początkujących nie jasno napisane jak cholera, niektóre rzeczy biorą się z kosmosu i nie bardzo wiadomo co się z czym je :/
no chyba ze dla ludzi którzy są oblatania w temacie, to ja przepraszam...

przykład w stylu Suggests
Niedziela 03 Grudzień 2006 1:35:42 am - unseen <mj.keepitreal_at_gmail.com>

genralnie ok, poza literówką - w kodzie klienta jest getstring - a powinno być getString.

No i w sumie to mam problem z biblioteka HTML_Ajax, przy zabawie na plikach php jest ok, ale rpzy łączeniu się z bazą mysql poprzez PHP nie wygląda to już tak dobrze...

ubiegłego roku?
Poniedziałek 31 Lipiec 2006 2:52:15 pm - mroq <mroq_at_irc.pl>

"Na szczęście od ubiegłego roku istnieje rozwiązanie wielu z tych problemów."

Chyba trochę dłużej o ile mnie pamięć nie myli.

Mentax.pl    NQ.pl- serwery z dodatkiem świętego spokoju...   
O nas | Kontakt | Mapa serwisu
Copyright (c) 2003-2022 php.pl    Wszystkie prawa zastrzeżone    Powered by eZ publish Content Management System eZ publish Content Management System