Miesi?czne archiwum: Wrzesień 2010

Autoloader w PHP

1. Wstęp

Pisząc aplikacje zorientowane obiektowo, zazwyczaj każdą klasę zapisujemy w osobnym pliku. Następnie w momencie gdy chcemy z którejś skorzystać, musimy ją ręcznie dołączyć, używając funkcji np.

 require_once(‘nazwa_pliku.php’)

Przy większych projektach takie dodawanie jest bardzo niepraktyczne, można nawet powiedzieć, że staje się udręką.

Rozwiązaniem tego problemu jest napisanie autoloader’a, który zajął by się automatycznym dołączeniem plików klas przy próbie  utworzenia instancji danej klasy. Aby tego dokonać, można użyć jednej z dwóch funkcji:

  • __autoload(), wymagane PHP >= 5
  • spl_autoload_register(), wymagane PHP >= 5.1.2

Jaka jest różnica pomiędzy tym dwoma funkcjami?

__autoload() W wersji PHP < 5.3.0 nie obsługuje w pełni wyjątków i nie jest dostępna jeżeli używamy PHP CLI.
Jeżeli potrzebujesz kilka funkcji autoload będziesz musiał użyć  spl_autoload_register().

No to teraz trochę praktyki:

2. __autoload()

Zaczniemy od utworzeniu pliku o nazwie np. autoload.php a w nim:

Dodajemy ścieżki do katalogów w których znajdują się nasze klasy, żeby parser wiedział gdzie ich szukać a nastepnie tworzymy funkcje __autoload(), która ładuje odpowiedni plik.

autoload.php

<?php
set_include_path(
        get_include_path()
        .PATH_SEPARATOR."./libs/"
        .PATH_SEPARATOR."./libs2/"
);
function __autoload($class_name) {
        echo 'Ładuję klase'.$class_name;
        require_once $class_name . '.php';
}
?>

Omówię jeszcze szybko  wybrane linie kodu

Linia 2: Funkcja  dodająca ścieżki do katalogu

Linia 3: Pobiera bieżące ścieżki do katalogu

Linia 4,5: Ścieżki do katalogu

Następnie mamy naszą funkcję __autoload która jako argument pobiera nazwę klasy do załadowania. Dla sprawdzenia kiedy się uruchomi nasz autoloader wypiszemy na ekranie która klasa jest ładowana a następnie ładujemy ją.

Teraz utwórzmy dwa katalogi libs i libs2 dla testów.

W katalogu libs tworzymy Class1.php

class Class1 {
    public function  __construct() {
        echo 'Klasa 1';
    }
}

A w katalogu libs2 tworzymy Class2.php

class Class2 {
    public function  __construct() {
        echo 'Klasa 2';
    }
}

Następnie w pliku index.php dołączamy ręcznie jeden jedyny plik z naszym autoloaderem i tworzymy obiekty danych klas:

<?php

require_once 'config/autoload.php';
$obj  = new Class1();
$obj2  = new Class2();
$obj3  = new Class1();

?>

Oto wyniki:

Ładuję klasę Class1
Klasa 1
Ładuję klasę Class2
Klasa 2
Klasa 1

Jak widać klasy się nam ładnie ładują . Gdy tworzymy ponownie obiekt klasy 1 nie jest uruchamiana funkcja __autoload, ponieważ plik został wcześniej dołączony przy okazji utworzenia wcześniejszego obiektu.

3. spl_autoload_register()

Ograniczeniem funkcji __autoload() jest to, że można mieć tylko jeden autoloader. A co jeśli chcemy wiecej? Wtedy naszym ratunkiem jest spl_autoload_register(), za pomocą którego rejestrujemy nasze własne „automatycznie ładowarki”.

Napiszemy jeszcze raz nasz plik autoload.php

 <?php
function autoload1($class_name) {
        echo 'Ładuję klasę '.$class_name."<br>";
        $file = "./inc/".$class_name . '.php';
        if(file_exists($file)){
            require_once $file;
        }
}

function autoload2($class_name) {
        echo 'Ładuję klasę '.$class_name."<br>";
        $file = "./inc2/".$class_name . '.php';
        if(file_exists($file)){
            require_once $file;
        }
}
?>

Jak widać usunęliśmy funkcję __autoload a w zamian za nie utworzyliśmy dwa własne autoloadery. I teraz zamiast ustawiać set_include_path() na odpowiednie katalogi, autoload1 wskazuje na jeden katalog a autoload2 wskazuje na drugi. Sprawdzamy czy istnieje plik który chcemy załadować i teraz albo ładuje albo nie robi nic.

Plik index.php wygląda teraz tak:

<?php

require_once 'config/autoload.php';

spl_autoload_register(autoload1);
spl_autoload_register(autoload2);

$obj  = new Class1();
$obj2  = new Class2();
$obj3  = new Class1();

?>

Jak widać rejestrujemy nasze loadery.

I teraz jeżeli nastąpi utworzenie obiektu którego plik nie został wcześniej dołączony uruchamia się autoload1. Jeżeli ten nie dołączy pliku uruchomi się autoload2, w przeciwnym wypadku autoload2 się nie uruchomi.

W niedalekiej przyszłości pokażę jak taki autoloader napisać obiektowo, z obsługą błędów oraz możliwością przeszukiwania folderów.

Pozdrawiam

Hello world!

Witam,

W pewnym momencie nauki programowania (tj. dzisiaj) naszła mnie potrzeba i chęć założenia własnego bloga. Będzie to dla mnie pewnego rodzaju archiwum tego co zrobiłem i z jakimi problemami się zmagałem.

Jakie tematy będę omawiał? PHP, bazy danych, jQuery (biblioteka dla języka JavaScript), CSS, może trochę o wzorcach projektowych… No, może tyle na początek, reszta wyjdzie w praniu.

Tak więc na początek powiem gromkie ‘HELLO WORLD’ i do przodu.

PHP

<?php

echo 'Hello world';

?>

JavaScript

<script type="text/javascript">

      $(document).ready(function(){

           alert('Hello world!');

      });

</script>

HTML

<html>
      <head>
            <title></title>
            <meta http-equiv="Content-Type" content="text/html;
                  charset=UTF-8">
      </head>
      <body>
            <p>Hello world!</p>
      </body>
</html>

Pozdrawiam