Dobra wiadomość dla oczekujących php 6 - spora część nowych funkcji zostanie zaimplementowana już w wersji 5.3, która jako ostatnia stabilna "piątka" ujrzy światło dzienne jeszcze w pierwszej połowie tego roku. Fakt ten ucieszy również osoby, których dostawca usług hostingowych zwlekać będzie z upgradem serwerów do php 6.
Poniżej prezentuję niektóre z nowych funkcji, których możemy się spodziewać w wersji 5.3.
<?php class User { public function set( $attribute, $value ) { ... } public function save() { ... } } $user = new User(); $user->set('fullname', 'Ben Balbo'); $user->save(); ?>
W przykładzie tym, metoda "save" nie koliduje z żadną inną metodą gdyż zawiera się w klasie "user". Pojawia się natomiast inny problem: klasa "user" może już być zdefiniowana w innej części systemu (np. jeśli nasz blog działa w obrębie większego systemu CMS). Rozwiązanie tej sytuacji przynosi słowo kluczowe "namespace", określające przestrzeń nazw:
<?php namespace MyCompany::Blog; class User { public function set( $attribute, $value ) { $this->$attribute = $value; } public function save() { echo '<p>Blog user ' . $this->fullname . ' saved</p>'; } } ?> <?php $user = new MyCompany::Blog::User(); $user->set('fullname', 'Ben Balbo'); $user->save(); ?>
Z pozoru, szufladkowanie naszych funkcji przy użyciu przestrzeni nazw nie daje zbyt wiele korzyści - zmiana "MyCompany_Blog_User" na "MyCompany::Blog::User" wydaje się mało istotna. Mimo to możemy teraz stworzyć klasę "user" dla systemu CMS w innej przestrzeni:
<?php namespace MyCompany::CMS; class User { public function set( $attribute, $value ) { $this->$attribute = $value; } public function save() { echo '<p>CMS user ' . $this->fullname . ' saved</p>'; } } ?>
W ten sposób umożliwiliśmy sobie użycie dwóch klas "MyCompany::Blog::User" i "MyCompany::CMS::User"
Używanie klas z wykorzystaniem pełnych nazw ich przestrzeni skutkuje dość długim kodem. Jeśli zamierzamy wywoływać wiele klas z przestrzeni "MyCompany::Blog", pisanie pełnej ścieżki za każdym razem może skutecznie uprzykrzyć kodowanie. W takim przypadku korzystnie jest wykorzystać słowo kluczowe "use". Rozpatrzmy poniższy kod, dodający nowy post:
<?php use MyCompany::Blog; $user = new Blog::User(); $post = new Blog::Post(); $post->setUser( $user ); $post->setTitle( $title ); $post->setBody( $body ); $post->save(); ?>
Za pomocą słowa "use" można również importować do skryptów pojedyncze klasy:
<?php use MyCompany::Blog::User; $user = new User(); ?>
Prędzej czy później konieczne będzie wykorzystanie dwóch klas o identycznych nazwach (ale innych przestrzeniach) w obrębie jednego skryptu. W takiej sytuacji moglibyśmy importować przestrzenie lub same klasy z wykorzystaniem aliasów, tak jak w poniższym przykładzie:
<?php use MyCompany::Blog::User as BlogUser; use MyCompany::CMS::User as CMSUser; $bloguser = new BlogUser(); $bloguser->set('fullname', 'John Doe'); $bloguser->save(); $cmsuser = new CMSUser(); $cmsuser->set('fullname', 'John Doe'); $cmsuser->save(); ?>
Stałe (constants) można będzie definiować z poziomu klasy. Oto przykład:
<?php namespace MyCompany; class Blog { const VERSION = '1.0.0'; } ?> <?php echo '<p>Blog bersion ' . MyCompany::Blog::VERSION . '</p>'; use MyCompany::Blog; echo '<p>Blog version ' . Blog::VERSION . '</p>'; use MyCompany::Blog::VERSION as Foo; echo '<p>Blog version ' . Foo . '</p>'; ?>
W dzisiejszych czasach coraz rzadziej używa się pojedynczych funkcji. Mimo to, możliwe jest przypisanie funkcji do wybranej przestrzeni. Oto przykład:
<?php namespace bundle; function foo() { echo '<p>This is the bundled foo</p>'; } foo(); // Wyświetli 'This is the bundled foo' ?><?php function foo() { echo '<p>This is the global foo</p>'; } require( 'lib/bundle.class.php'); bundle::foo(); // Wyświetli 'This is the bundled foo' foo(); // Wyświetli 'This is the global foo' ?>
Przestrzeń globalna jest warta rozpatrzenia jeśli używasz pojedynczych funkcji. Analizując powyższy przykład można stwierdzić, że nie ma żadnego sposobu aby wywołać globalną funkcję "foo" z poziomu kodu w przestrzeni "bundle".
Aby wywołania funkcji były w pełni poprawne można użyć bieżącej przestrzeni. Jeśli funkcja nie może być odnaleziona, poszukiwana będzie funkcja wewnętrzna o tej samej nazwie. Inne przestrzenie nie są przeszukiwane.
Aby wywołać globalną funkcję "foo" z poziomu przestrzeni "bundle" przywołujemy bezpośrednio przestrzeń globalną - podwójny dwukropek:
<?php namespace bundle; function foo() { echo '<p>This is the bundled foo</p>'; } foo(); // Wyświetli 'This is the bundled foo' ::foo(); // Wyświetli 'This is the global foo' ?>
Podczas definiowania funkcji "__autoload" (która załącza pliki klas na żądanie) posługujemy się zazwyczaj katalogiem zawierającym pliki klas. Możliwość użycia przestrzeni nazw wymaga rozszerzenia funkcji "__autoload", gdyż mogą pojawić się pliki klas o takich samych nazwach. Na szczęście funkcja "__autoload" wywoływana będzie z parametrem określającym również używaną przestrzeń.
__autoload( 'MyCompany::Blog::User' );
Zamieniając podwójne dwukropki na znak "/" lub "\" możemy z łatwością dołączyć pliki znajdujące się w podkatalogach:
function __autoload( $classname ) { $classname = strtolower( $classname ); $classname = str_replace( '::', DIRECTORY_SEPARATOR, $classname ); require_once( dirname( __FILE__ ) . '/' . $classname . '.class.php' ); }
Powyższy przykład dołączy plik "./classes/mycompany/blog/user.class.php".
Niebawem kolejna część artykułu.
Tego mi najbardziej brakuje w PHP. Jeszcze jedno zastosowanie Przestrzeni nazw można w koncu fragmenty kodu grupować w określone zestawy klas. Yupi! Zapewne ucieszy to w szczególności byłych lub aktualnych programistów C++, jeszcze brakuje wielokrotnego dziedziczenia i przejścia na pełną obiektowość oraz wymuszania typów np przy argumentach wejściowcyh funkcji. Nie mówię żeby język PHP był w pełni typowy tylko żeby pozwalał definiować że do funkcji może wejść w danej chwili tylko integer albo double i koniec... bo pisanie w środku dodatkowych funkcji typu is_int czy is_string jest wg mnie bez sensu i znacznie spowalnia aplikację :) ... czekam z niecierpliwością na PHP6 - bo nadchodzi rewolucja...
Mały błąd merytoryczny:
"Powyższy kod wyświetli:
Blog bersion 1.0.0
Blog version 1.0.0
Blog version Foo"
Powinno być:
"Powyższy kod wyświetli:
Blog bersion 1.0.0
Blog version 1.0.0
Blog version 1.0.0"
Dzięki za te przykłady! Przydadzą się na pewno i takich informacji szukałem a znaleźć nie mogłem.
Bardzo fajniem, że się pojawiło infoa temat NS w php 5.3 - jakiś czas temu szukałem info i nie znalazłem ;/
więc
Bartek, :*