This post comes from the first version of this blog.
Please send me an email if anything needs an update. Thanks!
Konstruktor klasy jest specjalną funkcją uruchamianą automatycznie podczas tworzenia nowej instancji klasy, jednokrotnie w trakcie życia danego obiektu (oczywiście możemy potem w jawny sposób wywołać go w kodzie, jednakże nie jest to polecana praktyka programistyczna). W języku PHP to stwierdzenie także jest prawdziwe, aczkolwiek w wielu miejscach interpreter udowadnia nam, że z powodzeniem możemy potraktować konstruktor jak zwykłą funkcję.
Wstęp: Implementujemy interfejs w klasie.
Żeby nie być gołosłownym, weźmy pod uwagę przykładowy interfejs i implementującą go klasę:
|
|
Mamy tutaj dwie możliwości popełnienia błędu:
- sygnatura funkcji w klasie niezgodna z deklaracją w interfejsie, np:
- różna ilość parametrów,
- różne typy parametrów, jeśli wykorzystujemy type hinting.
- brak definicji (jednej lub większej ilości) funkcji implementowanego interfejsu w klasie.
Fatal error: Declaration of Foo::foo() must be compatible with that of IFoo::foo() in [path]/index.php on line [line]W drugim zostaniemy poinformowani, że:
Fatal error: Class Foo contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (IFoo::foo) in [path]/index.php on line [line]Ale cały czas mówiliśmy o funkcjach, a co z tytułowym konstruktorem?
Cel: Deklaracja konstruktora klasy w interfejsie.
Spróbujmy więc do pierwszego listingu dopisać konstruktor, deklarując go w interfejsie oraz "implementując" w klasie:
|
|
Da się? Oczywiście, że się da! Powyższy kod bezproblemowo zostanie wykonany przez interpreter, nie pozostawiając po sobie ani śladu błędu. Eclipse, z którego korzystam do pisania kodu, w tym przypadku nawet “podświetli” szarym trójkącikiem metodę __construct() w klasie Foo, a po najechaniu wyświetli dymek: “implements IFoo.__construct”.
Sprawdźmy jeszcze, czy jeśli wprowadzimy celowo błędy wymienione we wstępie, to interpreter zareaguje w podobny sposób - będzie to oznaczało, że faktycznie możemy potraktować konstruktor jak zwykłą funkcję.
Mieliśmy dwie możliwości popełnienia błędu, a więc:
- sygnatura funkcji w klasie niezgodna z deklaracją w interfejsie:
$foo = new Foo();
<ul>
<li>brak definicji (jednej lub większej ilości) funkcji implementowanego interfejsu w klasie:</li>
</ul>
```php
<?php
interface IFoo
{
public function __construct();
}
class Foo implements IFoo
{
// Fatal error: Class Foo contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (IFoo::__construct) in [path]/index.php on line [line]
}
$foo = new Foo();
Jak widać na wstawionych listingach (w komentarzach wstawiłem błędy, jakimi “rzuca” interpreter), postawione wyżej tezy są prawdziwe.
Po raz kolejny PHP zachowuje się w “ciekawy” sposób, którego musimy być świadomi, chcąc w pełni wykorzystać możliwości języka. Deklarowanie sygnatury konstruktora w implementowanym interfejsie może być np. pomocne w uściśleniu, jakie argumenty ma przyjmować konstruktor klasy konkretnej “strategii” we wzorcu Strategy.
Oczywiście możliwości jest wiele i zależą one jedynie od naszej wyobraźni. Jeśli przychodzi Wam na myśl jakiś ciekawy sposób wykorzystania informacji zebranych w niniejszym wpisie, podzielcie się nimi w komentarzach - z góry dziękuję!