<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>&#60;?blog &#187; interfejs</title>
	<atom:link href="https://blog.visionsoftware.pl/tag/interfejs/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.visionsoftware.pl</link>
	<description>...nie tylko o programowaniu</description>
	<lastBuildDate>Sun, 23 Mar 2014 19:23:43 +0000</lastBuildDate>
	<language>pl-PL</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	
	<item>
		<title>Podpowiadanie typów w PHP</title>
		<link>https://blog.visionsoftware.pl/programowanie-php/podpowiadanie-typow-w-php.html</link>
		<comments>https://blog.visionsoftware.pl/programowanie-php/podpowiadanie-typow-w-php.html#comments</comments>
		<pubDate>Sat, 31 Mar 2012 12:08:32 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[callable]]></category>
		<category><![CDATA[interfejs]]></category>
		<category><![CDATA[obiekt]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[podpowiadanie typów]]></category>
		<category><![CDATA[tablica]]></category>
		<category><![CDATA[type hinting]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=554</guid>
		<description><![CDATA[PHP nie wymaga precyzowania typu podczas definicji zmiennej. Jest on określany na podstawie kontekstu, w jakim ta zmienna została użyta, z możliwością automatycznych konwersji. Możemy także samodzielnie zmieniać typ zmiennej poprzez rzutowanie lub odpowiednie funkcje. Rodzi to problemy szczególnie przy przekazywaniu parametrów do funkcji, jednak w tym przypadku można dla niektórych stosować podpowiadanie typów (ang. type hinting). W PHP mamy do dyspozycji łącznie 9 typów zmiennych: 4 typy proste &#8211; logiczny, całkowity, zmiennoprzecinkowy i znakowy [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>PHP nie wymaga precyzowania typu podczas definicji zmiennej. Jest on określany na podstawie kontekstu, w jakim ta zmienna została użyta, z możliwością automatycznych konwersji. Możemy także samodzielnie zmieniać typ zmiennej poprzez rzutowanie lub odpowiednie funkcje. Rodzi to problemy szczególnie przy przekazywaniu parametrów do funkcji, jednak w tym przypadku można dla niektórych stosować podpowiadanie typów (ang. <em>type hinting</em>).<span id="more-554"></span></p>
<p>W PHP mamy do dyspozycji łącznie 9 typów zmiennych:</p>
<ul>
<li>4 typy proste &#8211; logiczny, całkowity, zmiennoprzecinkowy i znakowy</li>
<li>2 złożone – tablicowy i obiektowy</li>
<li>3 specjalne – identyfikator zasobu (<code>resorce</code>), pusty (<code>NULL</code>) oraz wywoływalny (<code>callable</code>)</li>
</ul>
<p>Podpowiadanie typów w PHP nie umożliwia niestety rozpoznawania wszystkich wymienionych powyżej. Od wersji 5 języka możemy to robić dla obiektów, interfejsów, tablic (od PHP 5.1), oraz parametrów wywoływalnych (PHP 5.4).</p>
<p>Podpowiadanie typów możemy stosować w zwykłych funkcjach, oraz metodach klas. Wystarczy w tym celu przed nazwą zmiennej podać oczekiwany typ (<code>array</code>, <code>callable</code>, nazwę konkretnej klasy lub interfejsu)</p>
<h3>Podpowiadanie typów &#8211; obiekty</h3>
<p>W przypadku podpowiadania typów obiektowych należy pamiętać o bardzo ważnej rzeczy: jeśli parametrem musi być konkretna klasa lub interfejs, dozwoleni są także ich potomkowie, uczestniczący w hierarchii dziedziczenia.</p>
<p>Gdy zostanie określony wymagany typu obiektu, przekazanie innego spowoduje powstanie błędu. Zostało to pokazane na poniższym przykładzie:</p>
<pre class="brush: php; title: ; notranslate">
class Factory{
	public function produce(Product $product){
		print &quot;Produkuję &quot; . get_class($product);
	}
}

class Stock{
	/* ... */
}

class Product{
	/* ... */
}

class Car extends Product{
	/* ... */
}

class Motorbike extends Product{
	/* ... */
}

$factory = new Factory();
$stock = new Stock();
$car = new Car();
$motorbike = new Motorbike();

$factory-&gt;produce($car);
$factory-&gt;produce($motorbike);
$factory-&gt;produce($stock);
</pre>
<p>Zdefiniowane zostały klasy: <code>Factory</code>, <code>Stock</code>, <code>Product</code> oraz dziedziczące po nim <code>Car</code> oraz <code>Motorbike</code>. Klasa fabryki posiada zdefiniowaną jedną metodę, odpowiadającą za produkcję. Wymaga ona przekazania obiektu typu <code>Product</code>. Na powyższym listingu przekazano do niej natomiast dozwolone parametry wywodzące się z klasy <code>Product</code>, ale na koniec omyłkowo także <code>Stock</code>. Efekt będzie następujący:</p>
<pre class="brush: xml; light: true; title: ; notranslate">
Produkuję Car
Produkuję Motorbike
Fatal error: Argument 1 passed to Factory::produce() must be an instance of 
Product, called in typehinting.php on line 31 and defined in typehinting.php 
on line 3
</pre>
<p>Jak wspomniano już wcześniej, podpowiadanie typów w przypadku obiektów działa zarówno dla utworzonych bezpośrednio, jak i dziedziczących po określonym w definicji. Poprawne będzie więc też następujące wywołanie:</p>
<pre class="brush: php; title: ; notranslate">
$factory = new Factory();
$product = new Product();

$factory-&gt;produce($product);
</pre>
<p>W powyższym przypadku może nie jest to do końca pożądane, jednak w praktyce częściej będziemy oczekiwali obiektów klas dziedziczących. Oczywiście, gdy tego chcemy, możemy zawęzić wymagany typ tylko do klasy pochodnej.</p>
<pre class="brush: php; title: ; notranslate">
class Factory{
	public function produce(Car $product){
		print &quot;Produkuję tylko samochody&quot;;
	}
}
</pre>
<p>W przypadku podpowiadania typów można stosować także wartości domyślne. Jeśli w naszej fabryce przewidujemy strajk, możemy posłużyć się następującą definicją:</p>
<pre class="brush: php; title: ; notranslate">
class Factory{
	public function produce(Product $product = null){
		print &quot;Produkuję&quot; . get_class($product);
	}
}

$factory = new Factory();
$factory-&gt;produce();
</pre>
<p>Analogicznie do powyższych informacji, podpowiadanie typów może być używane także w przypadku interfejsów. Wystarczy określić, że parametr musi implementować jeden ze zdefiniowanych. Aby zobrazować tą możliwość, dokonamy pewnych zmian klas z pierwszego przykładu. Otóż w naszej fabryce w Indiach zamierzamy wyprodukować limitowaną wersję samochodu, o zwiększonej mocy silnika. Klasa fabryki otrzyma więc dodatkową możliwość produkcji, a specyfikacja samochodu zostanie odpowiednio zmodyfikowana poprzez implementację interfejsu (pominięto tu klasy zdefiniowane w pierwszym przykładzie):</p>
<pre class="brush: php; title: ; notranslate">
interface limitedEdition{
	public function engineImprovements();
}

class carSpecial extends car implements limitedEdition{
	public function engineImprovements(){
		print &quot;Zwiększona moc silnika&quot;;
	}
}

class FactoryIndia extends Factory {
	public function produceSpecialCar(limitedEdition $car){
		print &quot;Produkuję limitowaną wersję samochodu.&quot;;
	}
}

$factoryIndia = new FactoryIndia();
$car = new car();
$carSpecial = new carSpecial();

$factoryIndia-&gt;produceSpecialCar($carSpecial);
$factoryIndia-&gt;produce($car);
$factoryIndia-&gt;produceSpecialCar($car);
</pre>
<p>Efekt wywołania kodu będzie następujący:</p>
<pre class="brush: xml; light: true; title: ; notranslate">
Produkuję limitowaną wersję samochodu.
Produkuję Car
Fatal error: Argument 1 passed to FactoryIndia::produceSpecialCar() must implement 
interface limitedEdition, called in typehinting.php5 on line 43 and defined in 
typehinting.php on line 32
</pre>
<p>Jak widać, najpierw wyprodukowano edycję limitowaną samochodu przy użyciu nowej linii produkcyjnej, a następnie powrócono do wersji zwykłej. W kolejnym kroku, w wyniku błędu pracownika, uruchomiono jednak ponownie zmodyfikowaną linię produkcyjna dla wersji podstawowej samochodu, co oczywiście zostało szybko wychwycone przez inspektorów kontroli jakości.</p>
<h3>Podpowiadanie typów &#8211; tablice</h3>
<p>Sytuacja jest analogiczna do opisywanych powyżej możliwości w przypadku obiektów. Poniższy przykład obrazuje w jaki sposób zastrzec, aby zdefiniowana funkcja akceptowała jako parametr tylko tablicę:</p>
<pre class="brush: php; title: ; notranslate">
function needArray(array $param){
	print_r($param);
}

$array = array(1, 2, 3);

needArray($array);
</pre>
<p>Możemy także określić domyślą tablicę, dzięki czemu możliwe będzie wywołanie funkcji bez żadnego parametru:</p>
<pre class="brush: php; title: ; notranslate">
function needArray(array $param = array(7, 8, 9)){
	print_r($param);
}
</pre>
<h3>Podpowiadanie typów &#8211; callable</h3>
<p>Jest to najnowsza możliwość podpowiadania typów, wprowadzona w PHP 5.4. Dzięki niej można określić, że parametr przekazywany do funkcji lub metody musi być wywoływalny. Ma to zastosowanie w przypadku stosowania callbacków oraz funkcji anonimowych.</p>
<pre class="brush: php; title: ; notranslate">
function myFunction(callable $callback) {
	echo &quot;Wywołuję callback: &quot; . $callback();
}

myFunction(function() { return 'Witaj!'; });
</pre>
<h3>Podsumowanie</h3>
<p>Jak widać na przedstawionych przykładach, wykorzystanie podpowiadania typów jest niezwykle przydatne i znacznie upraszcza tworzony kod. Nie musimy aż tak wnikliwie sprawdzać przekazywanych argumentów przy pomocy <code>is_array()</code> lub <code>instanceof</code>. Mam nadzieję, że w <em>type hinting</em> w kolejnych wersjach PHP zostanie rozszerzone o typy proste.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/programowanie-php/podpowiadanie-typow-w-php.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
