leszek Sat May 25 05:06:29 2002 EDT Added files: /phpdoc-pl/language control-structures.xml Log: [qrak] language/control-structures.xml - en v. 1.58 DONE! [qrak] At last... :-)
Index: phpdoc-pl/language/control-structures.xml +++ phpdoc-pl/language/control-structures.xml <?xml version="1.0" encoding="iso-8859-2"?> <!-- EN-Revision: 1.58 Maintainer: Qrak Status: ready --> <!-- $Revision: 1.1 $ --> <chapter id="control-structures"> <title>Struktury kontrolne</title> <simpara> Każdy skrypt PHP zbudowany jest z wyrażeń. Wyrażeniem może być przypisanie, odwołanie do funkcji, pętla, wyrażenie warunkowe, a nawet wyrażenie, które nic nie robi (puste wyrażenie). Wyrażenia zwykle kończą się znakiem średnika. Dodatkowo, wyrażenia mogą być grupowane przez umieszczenie ich w nawiasach sześciennych. Grupa wyrażeń sama także jest wyrażeniem. W tym rozdziale opisano rozmaite rodzaje wyrażeń. </simpara> <sect1 id="control-structures.if"> <title><literal>if</literal></title> <para> Instrukcja <literal>if</literal> (jeżeli) jest jednym z najważniejszych mechanizmów dostępnych w wielu językach z PHP włącznie. Pozwala na wyodrębnienie fragmentu kodu, który zostanie wykonany pod określonym warunkiem. Instrukcja <literal>if</literal> w PHP jest bardzo podobna do swojego odpowiednika z języka C: <informalexample> <programlisting> <![CDATA[ if (warunek) wyrażenie ]]> </programlisting> </informalexample> </para> <simpara> Jak opisano w <link linkend="language.expressions">rozdziale na temat wyrażeń</link>, obliczana jest wartość logiczna wyrażenia <replaceable>warunek</replaceable>. Jeśli <replaceable>warunek</replaceable> jest równy &true; <replaceable>wyrażenie</replaceable> zostanie wykonane; w przeciwnym razie zostanie pominięte. Więcej informacji na temat obliczania logicznych wartości wyrażeń w rozdziale <link linkend="language.types.boolean.casting">'Konwersja do typu boolowskiego'</link>. </simpara> <para> Poniższy przykład wyświetli napis <computeroutput>a jest większe niż b</computeroutput>, jeśli <replaceable>$a</replaceable> będzie większe od <replaceable>$b</replaceable>: <informalexample> <programlisting role="php"> <![CDATA[ if ($a > $b) print "a jest większe niż b"; ]]> </programlisting> </informalexample> </para> <para> Często potrzeba, aby więcej niż jedna instrukcja była wykonana pod przyjętym warunkiem. Nie ma oczywiście potrzeby umieszczać każdej z tych instrukcji w osobnej strukturze <literal>if</literal>. Zamiast tego należy zgrupować te instrukcje za pomocą instrukcji grupującej. Na przykład poniższy kod wyświetli <computeroutput>a jest większe niż b</computeroutput>, jeżeli <replaceable>$a</replaceable> jest większe niż <replaceable>$b</replaceable>, i przypisze wartość <replaceable>$a</replaceable> do <replaceable>$b</replaceable>: <informalexample> <programlisting role="php"> <![CDATA[ if ($a > $b) { print "a jest większe niż b"; $b = $a; } ]]> </programlisting> </informalexample> </para> <simpara> Instrukcje <literal>if</literal> mogą być dowolnie umieszczane wewnątrz innych instrukcji <literal>if</literal>, co zapewnia autorowi programu kompletną elastyczność przy ustalaniu warunkowego wykonywania poszczególnych części programu. </simpara> </sect1> <sect1 id="control-structures.else"> <title><literal>else</literal></title> <para> Często potrzeba wykonać jedną instrukcję programu, gdy pewien warunek jest spełniony, lub inną inną, gdy ten sam warunek nie jest spełniony. Służy do tego instrukcja <literal>else</literal>. <literal>else</literal> rozszerza możliwości instrukcji <literal>if</literal> do sytuacji kiedy warunek opisany przy instrukcji <literal>if</literal> ma wartość &false;. Na przykład poniższy kod wyświetli <computeroutput>a jest większe niż b</computeroutput> jeżeli <replaceable>$a</replaceable> jest większe niż <replaceable>$b</replaceable>, lub <computeroutput>a NIE jest większe niż b</computeroutput> w przeciwnym przypadku.: <informalexample> <programlisting role="php"> <![CDATA[ if ($a > $b) { print "a jest większe niż b"; } else { print "a NIE jest większe niż b"; } ]]> </programlisting> </informalexample> Kod zawarty w instrukcji <literal>else</literal> wykonywany jest tylko wówczas, kiedy wyrażenie logiczne przy instrukcji <literal>if</literal> ma wartość &false;, a jeśli w tej samej grupie znajdowały się też instrukcje <literal>elseif</literal> - tylko wówczas jeśli i w tych instrukcjach wyrażenia logiczne miały wartość &false; (Patrz także: instrukcja <link linkend="control-structures.elseif">elseif</link>). </para> </sect1> <sect1 id="control-structures.elseif"> <title><literal>elseif</literal></title> <para> Instrukcja <literal>elseif</literal>, jak sama jej nazwa wskazuje, stanowi połączenie instrukcji <literal>if</literal> i <literal>else</literal>. Podobnie jak <literal>else</literal> rozszerza instrukcję <literal>if</literal> do sytuacji, kiedy wyrażenie logiczne stojące przy <literal>if</literal> ma wartość &false;. Jednakże w przeciwieństwie do typowej instrukcji <literal>else</literal>, kod objęty tą instrukcją będzie wykonany, jeśli wyrażenie logiczne stojące przy tej instrukcji będzie miało wartość &true;. Poniższy przykład wyświetli <computeroutput>a jest większe niż b</computeroutput>, <computeroutput>a jest równe b</computeroutput> lub <computeroutput>a jest mniejsze niż b</computeroutput>: <informalexample> <programlisting role="php"> <![CDATA[ if ($a > $b) { print "a jest większe niż b"; } elseif ($a == $b) { print "a jest równe b"; } else { print "a jest mniejsze niż b"; } ]]> </programlisting> </informalexample> </para> <simpara> Można użyć kilku instrukcji <literal>elseif</literal> w jednym bloku instrukcji <literal>if</literal>. Wykonany wtedy będzie ten blok, który pierwszy będzie mieć wartość &true;. W PHP można też napisać 'else if' (dwoma słowami) zamiast 'elseif' (jednym słowem). Z punktu widzenia składni języka, wyrażenia te różnią się od siebie (jeśli znasz się na C, jest to ta sama różnica co w C), jednak wynik ich działania jest ten sam. </simpara> <simpara> Dana instrukcja <literal>elseif<literal> będzie wykonana tylko wówczas, jeśli wszystkie poprzedzające ją instrukcje <literal>if<literal> i <literal>elseif</literal> w danym bloku miały wartość logiczną &false;, a ona sama ma wartość logiczną &true;. </simpara> </sect1> <sect1 id="control-structures.alternative-syntax"> <title>Składnia alternatywna w strukturach kontrolnych</title> <para> PHP oferuje alternatywną składnię dla niektórych struktur kontrolnych, a dokładnie dla: <literal>if</literal>, <literal>while</literal>, <literal>for</literal>, <literal>foreach</literal> i <literal>switch</literal>. W każdym przypadku podstawowa forma składni alternatywnej polega na zamianie nawiasu otwierającego na dwukropek (:), a nawiasu zamykającego na odpowiednie słowo: <literal>endif;</literal>, <literal>endwhile;</literal>, <literal>endfor;</literal>, <literal>endforeach;</literal> lub <literal>endswitch;</literal>. <informalexample> <programlisting role="php"> <![CDATA[ <?php if ($a == 5): ?> A jest równe 5 <?php endif; ?> ]]> </programlisting> </informalexample> </para> <simpara> W przykładzie powyżej, blok HTML "A jest równe 5" jest zagnieżdżony w instrukcji <literal>if</literal> napisanej w składni alternatywnej. Ten fragment kodu HTML zostanie wyświetlony tylko wówczas, kiedy $a będzie równe 5. </simpara> <para> Alternatywna składnia obejmuje też wyrażenia <literal>else<literal> i <literal>elseif<literal>. Poniższy przykład prezentuje obydwa wyrażenia zapisane przy pomocy składni alternatywej: <informalexample> <programlisting role="php"> <![CDATA[ if ($a == 5): print "a jest równe 5"; print "..."; elseif ($a == 6): print "a jest równe 6"; print "!!!"; else: print "a jest różne od 5 lub 6"; endif; ]]> </programlisting> </informalexample> </para> <para> Więcej przykładów w rozdziałach: <link linkend="control-structures.while">while</link>, <link linkend="control-structures.for">for</link>, i <link linkend="control-structures.if">if</link>. </para> </sect1> <sect1 id="control-structures.while"> <title><literal>while</literal></title> <para> Pętla <literal>while</while> jest najprostrzym typem pętli w PHP. Zachowuje się ona identycznie jak jej odpowiednik z języka C. Jej podstawowa forma wygląda następująco: <informalexample> <programlisting> <![CDATA[ while (wyrażenie) instrukcja ]]> </programlisting> </informalexample> </para> <simpara> Znaczenie instrukcji <literal>while</literal> jest bardzo proste. Nakazuje ona PHP tyle razy wykonywać określone instrukcje, jak długo wyrażenie przy słowie <literal>while</lieral> ma wartość &true;. Wartość tego wyrażenia jest sprawdzana za każdym razem na początku wykonywania nowej iteracji pętli, więc jeśli jego wartość zmieni się w trakcie wykonywania instrukcji, wykonanie całej pętli nie skończy się do momentu zakończenia całej iteracji. Jedna iteracja jest to jednokrotne wykonanie wszystkich instrukcji w pętli. Jeśli wyrażenie logiczne ma wartość &false; już na samym początku, instrukcje wewnątrz pętli nie będą w ogóle wykonane. </simpara> <para> Podobnie jak w instrukcji <literal>if</literal>, w pętli <literal>while</literal> można grupować instrukcje za pomocą nawiasów klamrowych, lub przez użycie składni alternatywnej: <informalexample> <programlisting> <![CDATA[ while (wyrażenie): instrukcja; instrukcja; ... endwhile; ]]> </programlisting> </informalexample> </para> <para> Poniższe przykłady są identyczne i obydwa wyświetlają liczby od 1 do 10: <informalexample> <programlisting role="php"> <![CDATA[ /* przykład 1*/ $i = 1; while ($i <= 10) { print $i++; /* zmienna $i będzie inkrementowana po wyświetleniu (post-inkrementacja) */ } /* przykład 2 */ $i = 1; while ($i <= 10): print $i; $i++; endwhile; ]]> </programlisting> </informalexample> </para> </sect1> <sect1 id="control-structures.do.while"> <title><literal>do..while</literal></title> <simpara> Pętla <literal>do..while</literal> zachowuje się bardzo podobnie do pętli <literal>while</literal>, z wyjątkiem tego, że wartość wyrażenia logicznego sprawdzana jest na końcu iteracji, a nie na początku. Wynikającą z tego główną różnicą jest to, że pierwsza iteracja w pętli <literal>do..while</literal> na pewno zostanie wykonana (gdyż wyrażenie logiczne będzie sprawdzone dopiero na koniec iteracji). Natomiast w pętli <literal>while</literal>, gdzie wyrażenie logiczne jest sprawdzane na początku iteracji, może dojść do sytuacji, że pętla w ogóle nie zostanie wykonana, jeśli to wyrażenie będzie miało wartość &false; od początku. </simpara> <para> Pętla <literal>do..while</literal> ma tylko jeden rodzaj składni: <informalexample> <programlisting role="php"> <![CDATA[ $i = 0; do { print $i; } while ($i>0); ]]> </programlisting> </informalexample> </para> <simpara> Powyższa pętla zostanie wykonana tylko raz, gdyż po pierwszej iteracji, wartość wyrażenia logicznego wynosić będzie &false; ($i nie jest większe od 0) i pętla zostanie zakończona. </simpara> <para> Zaawansowani programiści C są zaznajomieni z innym wykorzystaniem pętli <literal>do..while</literal>, które służy do przerwania wykonywania bloku instrukcji w określonym momencie przez użycie <literal>do..while</literal>(0) i instrukcji <link linkend="control-structures.break"><literal>break</literal></link>. Demonstruje to poniższy kod: <informalexample> <programlisting role="php"> <![CDATA[ do { if ($i < 5) { print "i jest za małe"; break; } $i *= $factor; if ($i < $minimum_limit) { break; } print "i jest w porządku"; ...operacje na i... } while(0); ]]> </programlisting> </informalexample> </para> <simpara> Nie przejmuj się, jeśli nie rozumiesz tego do końca lub w ogóle. Możesz tworzyć skrypty, nawet zaawansowane skrypty bez użycia tego 'mechanizmu'. </simpara> </sect1> <sect1 id="control-structures.for"> <title><literal>for</literal></title> <para> Pętla <literal>for</literal> jest najbardziej skomplikowanym rodzajem pętli w PHP. Zachowuje się identycznie jak jej odpowiedniki z C. Jej składnia wygląda następująco: <informalexample> <programlisting> <![CDATA[ for (wyrażenie1; wyrażenie2; wyrażenie3) instrukcje ]]> </programlisting> </informalexample> </para> <simpara> <replaceable>wyrażenie1</replaceable> jest wykonywane tylko raz, na początku pętli. </simpara> <simpara> Na początku każdej nowej iteracji, obliczana jest wartość logiczna wyrażenia <replaceable>wyrażenie2</replaceable>. Jeśli wynikiem obliczenia jest &true;, to pętla kontynuuje i następuje wykonanie instrukcji umieszczonych w pętli. Jeśli jednak wyrażenie ma wartość &false;, to wykonanie pętli zostaje przerwane. </simpara> <simpara> Na końcu każdej iteracji zostaje wykonane <replaceable>wyrażenie3</replaceable>. </simpara> <simpara> Każde z wyrażeń może być puste. Puste <replaceable>wyrażenie2</replaceable> oznacza, że pętla jest nieskończona (PHP interpretuje to jako wartość &true;, podobnie z resztą jak C). Nie jest to jednak tak bezużyteczne, jak to się może wydawać, gdyż często stosuje się to w połączeniu z instrukcją <link linkend="control-structures.break"></literal>break</literal></link>, co zastępuje <replaceable>wyrażenie2</replaceable> w pętli <literal>for</literal>. </simpara> <para> Wszystkie poniższe przykłady wyświetlają liczby od 1 do 10. Proszę zauważyć rozmaite odmiany składni: <informalexample> <programlisting role="php"> <![CDATA[ /* przykład 1 */ for ($i = 1; $i <= 10; $i++) { print $i; } /* przykład 2 */ for ($i = 1;;$i++) { if ($i > 10) { break; } print $i; } /* przykład 3 */ $i = 1; for (;;) { if ($i > 10) { break; } print $i; $i++; } /* przykład 4 */ for ($i = 1; $i <= 10; print $i, $i++); ]]> </programlisting> </informalexample> </para> <simpara> Oczywiście najzgrabniejsza składnia jest w przykładzie pierwszym (albo czwartym), ale w wielu sytuacjach puste wyrażenia w pętli <literal>for</literal> bardzo się przydają. </simpara> <para> PHP obsługuje również składnię alternatywną (z dwukropkiem) w pętli <literal>for</literal>. <informalexample> <programlisting> <![CDATA[ for (wyrażenie1; wyrażenie2; wyrażenie3): instrukcja; ...; endfor; ]]> </programlisting> </informalexample> </para> <para> Inne języki programowania posiadają pętlę <literal>foreach</literal> do obsługi tablic itp. W PHP 3 nie ma takiej pętli, natomiast została ona dodana do PHP 4. Więcej na ten temat w odpowiednim <link linkend="control-structures.foreach">rozdziale</link>. W PHP 3 można połączyć instrukcje <link linkend="control-structures.while">while</link>, <function>list</function> i <function>each</function> co pozwoli osiągnąć ten sam efekt. Przykłady na to znajdują się w rozdziałach dotyczących wyżej wymienionych instrukcji. </para> </sect1> <sect1 id="control-structures.foreach"> <title><literal>foreach</literal></title> <para> PHP 4 zawiera, czego brak w PHP 3, konstrukcję <literal>foreach</literal>, podobną do jej odpowiedników z Perla i innych języków. Pętla ta umożliwia łatwą iterację wewnątrz tablic. Istnieją dwie składnie tej konstrukcji, przy czym druga jest mniej ważnym, lecz użytecznym rozszerzeniem pierwszej: <informalexample> <programlisting> <![CDATA[ foreach(wyrażenie_tablicowe as $wartość) wyrażenie foreach(wyrażenie_tablicowe as $klucz => $wartość) wyrażenie ]]> </programlisting> </informalexample> </para> <simpara> Pierwsza odmiana iteruje wewnątrz tablicy podanej w <literal>wyrażenie_tablicowe</literal>. Przy każdej iteracji, wartość aktualnego elementu tablicy jest przypisywana do zmiennej <literal>$wartość</literal>, a wewnętrzny wskaźnik tablicy jest przesuwany o jeden (więc w następnej iteracji przypisany zostanie kolejny element tablicy). </simpara> <simpara> Druga odmiana działa tak samo jak pierwsza, przy czym klucz aktualnego elementu tablicy zostanie przypisany do zmiennej <literal>$klucz</literal> w każdej iteracji. </simpara> <para> <note> <para> Kiedy rozpoczyna się wykonywanie pętli <literal>foreach</literal>, wewnętrzny wskaźnik tablicy jest automatycznie resetowany, co ustawia go na pierwszym elemencie tablicy. Oznacza to, że nie trzeba wywoływać komendy <function>reset</function> przed rozpoczęciem pętli <literal>foreach</literal>. </para> </note> </para> <para> <note> <para> Proszę także pamiętać, że konstrukcja <literal>foreach</literal> operuje na kopii tablicy, a nie na oryginale, więc położenie wskaźnika tablicy nie jest modyfikowane jak w konstrukcji <function>each</function>, a zmiany dokonane na pobranym elemencie tablicy nie oddziałują na oryginalną tablicę. </para> </note> </para> <note> <para> <literal>foreach</literal> nie pozwala na ukrycie komunikatów o błędach za pomocą '@'. </para> </note> <para> Można zauważyć, że poniższe przykłady są funkcjonalnie identyczne: <informalexample> <programlisting role="php"> <![CDATA[ reset ($tabl); while (list(, $wartość) = each ($tabl)) { echo "Wartość: $wartość<br>\n"; } foreach ($tabl as $wartość) { echo "Wartość: $wartość<br>\n"; } ]]> </programlisting> </informalexample> Poniższe przykłady są również funkcjonalnie identyczne: <informalexample> <programlisting role="php"> <![CDATA[ reset ($tabl); while (list($klucz, $wartość) = each ($tabl)) { echo "Klucz: $klucz; Wartość: $wartość<br>\n"; } foreach ($tabl as $klucz => $wartość) { echo "Klucz: $klucz; Wartość: $wartość<br>\n"; } ]]> </programlisting> </informalexample> </para> <para> Więcej przykładów demonstrujących użycie tej pętli: <informalexample> <programlisting role="php"> <![CDATA[ /* przykład 1 foreach: tylko wartość */ $a = array (1, 2, 3, 17); foreach ($a as $v) { print "Aktualna wartość \$a: $v.\n"; } /* przykład 2 foreach: wartość (z kluczem generowanym dla potrzeb ilustracji)*/ $a = array (1, 2, 3, 17); $i = 0; /* tylko dla potrzeb ilustracyjnych */ foreach($a as $v) { print "\$a[$i] => $v.\n"; $i++; } /* przykład 3 foreach: klucz i wartość */ $a = array ( "jeden" => 1, "dwa" => 2, "trzy" => 3, "siedemnaście" => 17 ); foreach($a as $k => $v) { print "\$a[$k] => $v.\n"; } /* przykład 4 foreach: tablice wielowymiarowe */ $a[0][0] = "a"; $a[0][1] = "b"; $a[1][0] = "y"; $a[1][1] = "z"; foreach($a as $v1) { foreach ($v1 as $v2) { print "$v2\n"; } } /* przykład 5 foreach: tablice dynamiczne */ foreach(array(1, 2, 3, 4, 5) as $v) { print "$v\n"; } ]]> </programlisting> </informalexample> </para> </sect1> <sect1 id="control-structures.break"> <title><literal>break</literal></title> <simpara> <literal>break</literal> zakańcza wykonywanie aktualnej instrukcji <literal>for</literal>, <literal>foreach</literal> <literal>while</literal>, <literal>do..while</literal> lub <literal>switch</literal>. </simpara> <simpara> <literal>break</literal> akceptuje opcjonalny argument, który mówi, ile zagnieżdzonych struktur kontrolnych ma zostać przerwanych w danym momencie. </simpara> <para> <informalexample> <programlisting role="php"> <![CDATA[ $arr = array ('jeden', 'dwa', 'trzy', 'cztery', 'stop', 'pięć'); while (list (, $val) = each ($arr)) { if ($val == 'stop') { break; /* Można tu też napisać: 'break 1;' */ } echo "$val<br>\n"; } /* Użycie opcjonalnego argumentu: */ $i = 0; while (++$i) { switch ($i) { case 5: echo "Na 5<br>\n"; break 1; /* Wyjdź tylko ze switch. */ case 10: echo "Na 10; wyjście<br>\n"; break 2; /* Wyjdź ze switch i z while. */ default: break; } } ]]> </programlisting> </informalexample> </para> </sect1> <sect1 id="control-structures.continue"> <title><literal>continue</literal></title> <simpara> <literal>continue</literal> używane jest wewnątrz instukcji pętli do przerwania wykonywania danej iteracji pętli i rozpoczęcia zupełnie nowej iteracji. </simpara> <simpara> <literal>continue</literal> akceptuje opcjonalny argument liczbowy, który mówi, ilu poziomów zagnieżdżonych pętli dana instrukcja <literal>continue</literal> dotyczy. </simpara> <para> <informalexample> <programlisting role="php"> <![CDATA[ while (list ($klucz, $wartość) = each ($arr)) { if (!($klucz % 2)) { // opuść klucze nieparzyste continue; } zrób_coś_z_nieparzystymi ($wartość); } $i = 0; while ($i++ < 5) { echo "Zewnętrzna<br>\n"; while (1) { echo " Środkowa<br>\n"; while (1) { echo " Wewnętrzna<br>\n"; continue 3; } echo "To się nigdy nie wyświetli.<br>\n"; } echo "Ani to.<br>\n"; } ]]> </programlisting> </informalexample> </para> </sect1> <sect1 id="control-structures.switch"> <title><literal>switch</literal></title> <simpara> Instrukcja <literal>switch</literal> jest podobna do serii instrukcji IF z warunkiem na to samo wyrażenie. W wielu przypadkach istnieje potrzeba porównania jednej zmiennej (lub wyrażenia) z wieloma różnymi wartościami i wykonania różnych fragmentów kodu, w zależności od wyniku porównania tej zmiennej z różnymi wartościami. Do tego właśnie służy instrukcja <literal>switch</literal>. </simpara> <para> Poniżej znajdują się dwa przykłady wykonujące dokładnie to samo, przy czym jeden z nich wykorzystuje serię instrukcji <literal>if</literal>, zaś drugi używa instrukcji <literal>switch</literal>: <informalexample> <programlisting role="php"> <![CDATA[ if ($i == 0) { print "i jest równe 0"; } if ($i == 1) { print "i jest równe 1"; } if ($i == 2) { print "i jest równe 2"; } switch ($i) { case 0: print "i jest równe 0"; break; case 1: print "i jest równe 1"; break; case 2: print "i jest równe 2"; break; } ]]> </programlisting> </informalexample> </para> <para> Ważne jest by zrozumieć, jak działa instrukcja <literal>switch</literal>, żeby uniknąć błędów. Instrukcja <literal>switch</literal> jest wykonywana linia po linii (dokładnie wyrażenie po wyrażeniu). Na początku żaden fragment kodu nie jest wykonywany. Dopiero kiedy zostaje odnalezione wyrażenie <literal>case</literal>, którego wartość odpowiada wyrażeniu przy instrukcji <literal>switch</literal>, PHP rozpoczyna wykonywanie kodu od miejsca, gdzie znajduje się ta instrukcja <literal>case</literal>. PHP wykonuje instrukcje aż do momentu kiedy blok <literal>switch</literal> się skończy, lub do momentu znalezienia instrukcji <literal>break</literal>. Jeśli nie napiszesz instrukcji <literal>break</literal> na końcu instrukcji w danym wyrażeniu <literal>case</literal> to PHP będzie wykonywać dalej instrukcje z następnego wyrażenia <literal>case</literal>. Na przykład: <informalexample> <programlisting role="php"> <![CDATA[ switch ($i) { case 0: print "i jest równe 0"; case 1: print "i jest równe 1"; case 2: print "i jest równe 2"; } ]]> </programlisting> </informalexample> </para> <simpara> W tym przypadku, jeśli $i jest równe 0, to PHP wykona wszystkie trzy instrukcje print. Jeśli natomiast będzie równe jeden - wtedy tylko dwie ostatnie. Zachowanie zgodne z oczekiwaniami będzie wtedy, kiedy $i będzie równe 2 - wtedy wykonane będzie tylko ostatnia instrukcja print. Nie wolno zatem zapominać o umieszczaniu na końcu instrukcji <literal>break</literal>, chyba że planuje się wykorzystać jakieś specjalne możliwości instrukcji <literal>switch</literal>, o czym dalej. </simpara> <simpara> W instrukcji <literal>switch</literal> wartość wyrażenia jest obliczana tylko raz, a następnie jest porównywana z każdym z wyrażeń przy etykiecie <literal>case</literal>. Natomiast w instrukcji <literal>elseif</literal> wartość wyrażenia jest obliczana ponownie. Dlatego, jeśli twoje wyrażenie jest bardziej skomplikowane od zwykłego porównania, lub znajduje się w zwartej pętli (tight loop), <literal>switch</literal> może być szybszy. </simpara> <para> Po etykiecie case mogą nie występować żadne instrukcje, co oznacza po prostu, że sterowanie zostaje przekazane do następnej etykiety case. <informalexample> <programlisting role="php"> <![CDATA[ switch ($i) { case 0: case 1: case 2: print "i jest mniejsze od 3, ale nie jest ujemne"; break; case 3: print "i jest równe 3"; } ]]> </programlisting> </informalexample> </para> <para> Specjalną etykietą jest etykieta warunku domyślnego - <literal>default</literal>. Etykieta ta dotyczy sytuacji, w której wyrażenie nie pasowało do wartości przy innych etykietach typu <literal>case</litera>. W instrukcji <literal>switch</literal> ta etykieta powinna być ostatnia z listy. Na przykład: <informalexample> <programlisting role="php"> <![CDATA[ switch ($i) { case 0: print "i jest równe 0"; break; case 1: print "i jest równe 1"; break; case 2: print "i jest równe 2"; break; default: print "i jest różne od 0, 1 i 2"; } ]]> </programlisting> </informalexample> </para> <para> Etykieta <literal>case</literal> może zawierać dowolną wartość typu prostego, czyli liczbę całkowitą, zmiennoprzecinkową lub łańcuch znaków. Tablice lub obiekty nie mogą być użyte, o ile nie zostaną przekształcone w jakiś typ prosty. </para> <para> Instrukcja switch obsługuje też składnię alternatywną. Więcej informacji na ten temat w rozdziale <link linkend="control-structures.alternative-syntax">Składnia alternatywna w strukturach kontrolnych</link>. <informalexample> <programlisting role="php"> <![CDATA[ switch ($i): case 0: print "i jest równe 0"; break; case 1: print "i jest równe 1"; break; case 2: print "i jest równe 2"; break; default: print "i jest różne od 0, 1 i 2"; endswitch; ]]> </programlisting> </informalexample> </para> </sect1> <sect1 id="control-structures.declare"> <title><literal>declare</literal></title> <para> Instrukcja <literal>declare</literal> służy do ustawienia dyrektyw wykonawczych dla bloku kodu. Składnia instrukcji jest podobna do składni innych struktur kontrolnych: <informalexample> <programlisting> <![CDATA[ declare (dyrektywa) instrukcje ]]> </programlisting> </informalexample> </para> <para> Argument <literal>dyrektywa</literal> pozwala na ustawienie zachowania się danego bloku <literal>declare</literal>. W chwili obecnej rozpoznawana jest tylko jedna dyrektywa: <literal>ticks</literal>. (Więcej informacju na temat dyrektywy <link linkend="control-structures.declare.ticks">ticks</link> w dedykowanym podrozdziale). </para> <para> Kod zawarty w bloku <literal>instrukcje</literal> będzie wykonywany. Sposób i poboczne efekty wykonania tego kodu mogą zależeć od argumentu <literal>dyrektywa</literal>. </para> <sect2 id="control-structures.declare.ticks"> <title>Ticks</title> <para> Tyknięcie (tick) jest zdarzeniem, które następuje po każdych <replaceable>N</replaceable> niskopoziomowych instrukcjach wykonywanych przez parser wewnątrz bloku <literal>declare</literal>. Wartość parametru <replaceable>N</replaceable> jest określana przez umieszczenie wyrażenia <literal>ticks=<replaceable>N</replaceable></literal> wewnątrz argumentu <literal>dyrektywa</literal> danego bloku <literal>declare</literal>. </para> <para> Zdarzenie wywoływanie na każde tyknięcie określa się przez użycie funkcji <function>register_tick_function</function>. Więcej szczegółów znajduje się w poniższym przykładzie. Proszę pamiętać, że z każdym tyknięciem może być wywoływane więcej niż jedno zdarzenie. </para> <para> <example> <title>Profilowanie sekcji kodu PHP </title> <programlisting role="php"> <![CDATA[ <?php // funkcja, która zapisuje czas jej wywołania function profile ($wyrzuć = FALSE) { static $profile; // zwróć tablicę czasów wywołania i wykasuj jej lokalną kopię if ($wyrzuć) { $temp = $profile; unset ($profile); return ($temp); } $profile[] = microtime (); } // ustal wskaźnik tyknięcia register_tick_function("profile"); // zainicjowanie funkcji przed blokiem declare profile (); // wykonaj poniższy kod, generując tyknięcie co 2 instrukcje declare (ticks=2) { for ($x = 1; $x < 50; ++$x) { echo similar_text (md5($x), md5($x*$x)), "<br />"; } } // Wyświetl dane przechowywane w profilerze print_r (profile (TRUE)); ?> ]]> </programlisting> </example> Powyższy przykład profiluje kod PHP wewnątrz bloku "declare", zapisując czas wywołania co drugiej niskopoziomowej instrukcji w bloku instrukcji. Informację tę można wykorzystać do wykrycia fragmentów kodu wykonywanych w zbyt wolnym tempie. Problem wyszukania takich fragmentów można zrealizować na wiele sposobów, przy czym użycie tyknięć jest najwygodniesze i najłatwiejsze do zaimplementowania. </para> <simpara> Tyknięcia są doskonale przystosowane dla potrzeb debugowania, implementacji prostej wielozadaniowości, wykonywania operacji We/Wy w tle i wielu innych zadań. </simpara> <simpara> Patrz także <function>register_tick_function</function> i <function>unregister_tick_function</function>. </simpara> </sect2> </sect1> <sect1 id="function.return"> <title>return</title> <simpara> Instrukcja <function>return</function>, wywołana z wnętrza funkcji, natychmiastowo zakańcza wykonywanie tej funkcji i zwraca jako jej wartość swój argument. <function>return</function> zakańcza również wykonywanie instrukcji <function>eval</function> lub danego pliku skryptowego. </simpara> <simpara> Instrukcja ta, wywołana w zasięgu globalnym, zakańcza wykonywanie całego pliku skryptowego. Jeśli dany skrypt był dołączony funkcjami <function>include</function> lub <function>require</function>, sterowanie zostaje zwrócone do pliku wywołującego. Poza tym, jeśli plik został dołączony funkcją <function>include</function>, argument przekazany do funkcji <function>return</function> będzie zwrócony jako wartość funkcji <function>include</function>. Jeśli funkcja <function>return</function> zostanie wywołana w głównym pliku skryptowym, nastąpi zakończenie całego skryptu. Jeśli dany skrypt został wywołany przez dyrektywy konfiguracyjne <link linkend="ini.auto-prepend-file">auto_prepend_file</link> lub <link linkend="ini.auto-append-file">auto_append_file</link> w <link linkend="configuration.file">plik konfiguracyjnym</link>, wtedy wykonywnie tego pliku skryptowego zostanie zakończone. </simpara> <simpara>Więcej informacji w rozdziale <link linkend="functions.returning-values">zwracanie wartości</link>. </simpara> <note> <simpara> Proszę zauważyć, że ponieważ <function>return</function> jest konstrukcją językową a nie funkcją, nawiasy otaczające jej argumenty nie są konieczne. W rzeczywistości częściej są one opuszczane przez programistów, choć opuszczenie ich, czy nie, nie zmienia niczego. </simpara> </note> </sect1> <sect1 id="function.require"> <title><function>require</function></title> <simpara> Instrukcja <function>require</function> służy do wczytania i wykonania skryptu z określonego pliku. </simpara> <simpara> <function>require</function> wczytuje i wykonuje skrypt z podanego pliku. Szczegółowa informacja odnośnie tego, jak działa wczytywanie opisana jest w dokumentacji dla instrukcji <function>include</function>. </simpara> <simpara> Instrukcje <function>require</function> i <function>include</function> są identyczne w każdym szczególe, z wyjątkiem obsługi błędów. W razie niepowodzenia, <function>include</function> generuje ostrzeżenie (<link linkend="internal.e-warning">Warning</link>), podczas gdy <function>require</function> generuje błąd krytyczny (<link linkend="internal.e-error">Fatal Error</link>). Innymi słowy, instrukcji <function>require</function> używa się do wczytywania plików, które są niezbędne do działania skryptu i w przypadku ich braku wykonywanie skryptu musi zostać przerwane. Instukcja <function>include</function> nie zachowuje się w ten sposób. W jej przypadku, przy braku pliku wykonywanie skryptu będzie kontynuowane. Proszę również pamiętać o właściwym ustawieniu dyrektywy konfiguracyjnej <link linkend="ini.include-path">include_path</link>. </simpara> <para> <example> <title>Podstawowe przykłady użycia <function>require</function></title> <programlisting role="php"> <![CDATA[ <?php require 'nagłówek.php'; require $plik; require ('jakiś_plik.txt'); ?> ]]> </programlisting> </example> </para> <simpara> Więcej przykładów w dokumentacji instrukcji <function>include</function>. </simpara> <note> <simpara> Począwszy od PHP 4.0.2, zachowanie instrukcji jest następujące: <function>require</function> będzie zawsze próbować odczytać plik docelowy, nawet jeśli linia w której ona się znajduje nigdy nie zostanie wykonana. Instrukcja warunkowa nie wpływa na działanie <function>require</function>. Jednakże, jeśli linia, w której pojawia się <function>require</function> nie zostaje wykonana, zawartość pliku wczytywanego też nie zostaje wykonana. Podobnie, instrukcje pętli nie wpływają na działanie <function>require</function>. Chociaż kod zawarty w pliku docelowy wciąż jest podmiotem pętli, <function>require</function> działa tylko raz. </simpara> </note> <simpara> Patrz także <function>include</function>, <function>require_once</function>, <function>include_once</function>, <function>eval</function>, <function>file</function>, <function>readfile</function>, <function>virtual</function> i <link linkend="ini.include-path">include_path</link>. </simpara> </sect1> <sect1 id="function.include"> <title><function>include</function></title> <simpara> Instrukcja <function>include</function> służy do wczytania i wykonania kodu z określonego pliku w trakcie wykonywania skryptu. </simpara> <simpara> Poniższa dokumentacja dotyczy także instrukcji <function>require</function>. Obydwie instrukcje są identyczne w każdym szczególe, z wyjątkiem obsługi błędów. <function>include</function> generuje błąd typu <link linkend="internal.e-warning">Warning</link>, podczas gdy <function>require</function> generuje błąd <link linkend="internal.e-error">Fatal Error</link>. Innymi słowy, funkcji <function>require</function> używa się, by zatrzymać przetwarzanie skryptu, gdy brakuje jakiegoś pliku. Jeżeli zostanie użyta funkcja <function>include</function>, to w powyższej sytuacji skrypt będzie przetwarzany dalej. Proszę pamiętać o właściwym ustawieniu dyrektywy <link linkend="ini.include-path">include_path</link>. </simpara> <simpara> Kiedy plik zostanie wczytany instrukcją <function>include</function>, zawarty w nim kod dziedziczy <link linkend="language.variables.scope">zasięg zmiennych</link> po linii, w której znajdowała się instrukcja wczytania. Każda zmienna dostępna w linii z instrukcją <function>include</function> będzie dostępna we wczytywanym pliku od miejsca wczytania naprzód. </simpara> <para> <example> <title>Podstawowe wykorzystanie <function>include</function></title> <programlisting role="php"> <![CDATA[ vars.php <?php $kolor = 'zielone'; $owoc = 'jabłko'; ?> test.php <?php echo "Jedno $kolor $owoc"; // Jedno include 'vars.php'; echo "Jedno $kolor $owoc"; // Jedno zielone jabłko ?> ]]> </programlisting> </example> </para> <simpara> Jeśli instrukcja wczytania znajduje się wewnątrz deklaracji funkcji, to cały kod zawarty w pliku wczytywanym będzie zachowywał się, jakby był zdefiniowany wewnątrz tej funkcji. Znaczy to, że odziedziczy zasięg zmiennych po tej funkcji. </simpara> <para> <example> <title>Wczytywanie wewnątrz funkcji</title> <programlisting role="php"> <![CDATA[ <?php function foo() { global $kolor; include 'vars.php'; echo "Jeden $kolor $owoc"; } /* vars.php znajduje się w zasięgu foo(), więc * * $owoc NIE jest dostępny poza zasięgiem tej * * funkcji. Natomiast $kolor jest dostępny, * * ponieważ został zadeklarowany w zasięgu * * globalnym. */ foo(); // Jedno zielone jabłko echo "A $kolor $owoc"; // Jedno zielone ?> ]]> </programlisting> </example> </para> <simpara> Na początku wczytywanego pliku parsowanie wychodzi z trybu PHP do trybu HTML i wraca do trybu początkowego na końcu. Z tego powodu każdy kod wewnątrz wczytywanego pliku będzie wykonany jako kod PHP, o ile będzie zawarty w <link linkend="language.basic-syntax.phpmode">ważnych znacznikach początku i końca kodu PHP</link>. </simpara> <simpara> Jeśli "<link linkend="ini.allow-url-fopen">URL fopen wrappers</link>" są włączone w PHP (takie jest domyślne ustawienie) można podać nazwę pliku do wczytania używając adresu URL (przez protokół HTTP), zamiast podawać ścieżkę lokalną. Jeśli podany w adresie serwer interpretuje plik docelowy jako kod PHP, można do tego skryptu przekazać zmienne w taki sam sposób jak przy metodzie GET protokołu HTTP. Ściśle mówiąc, nie jest to to samo, co wczytywanie pliku lokalnego; jest to wykonanie pliku na zdalnym serwerze i wklejenie rezultatu jego działania do skryptu wywołującego. W tym przypadku, rzecz jasna, zasięg globalny zmiennych nie obejmuje pliku wczytywanego tą metodą. </simpara> <para> <example> <title><function>include</function> i protokół HTTP</title> <programlisting role="php"> <![CDATA[ <?php /* Przykład ten zakłada, że serwer www.example.com jest tak skonfigurowany, * że wykonuje skrypty w plikach .php natomiast nie wykonuje skryptów w plikach * .txt. Pojęcie 'działa', znaczy tutaj, że zmienne $foo i $bar są dostępne * we wczytywanym pliku */ // Nie działa: file.txt nie jest traktowany jak skrypt php include 'http://www.example.com/file.txt?foo=1&bar=2'; // Nie działa: PHP będzie szukać pliku o nazwie 'file.php?foo=1&bar=2' // w lokalnym systemie plików include 'file.php?foo=1&bar=2'; // Działa. include 'http://www.example.com/file.php?foo=1&bar=2'; $foo = 1; $bar = 2; include 'file.txt'; // Działa. include 'file.php'; // Działa. ?> ]]> </programlisting> </example> Patrz także <link linkend="features.remote-files">Korzystanie ze zdalnych plików</link>, <function>fopen</function> i <function>file</function>. </para> <para> Ponieważ <function>include</function> i <function>require</function> są specialnymi konstrukcjami językowymi, muszą być umieszczone w instrukcji grupującej, aby mogły działać w instrukcji warunkowej. </para> <para> <example> <title>include() i instrukcja warunkowa</title> <programlisting role="php"> <![CDATA[ <?php // Ten kod jest NIEPOPRAWNY i nie zadziała zgodnie z oczekiwaniami. if ($warunek) include $plik; else include $inny; // Natomiast ten kod jest POPRAWNY. if ($warunek) { include $plik; } else { include $inny; } ?> ]]> </programlisting> </example> </para> <simpara> Obsługa zwracanych wartości: można wywołać instrukcję <function>return</function> wewnątrz wczytywanego pliku, aby zakończyć jego wykonywanie i powrócić do pliku wywołującego. Można też zwracać wartości z wczytywanych plików, co upodabnia wczytywanie plików do wykorzystywania funkcji. </simpara> <note> <simpara> W PHP 3 instrukcja <function>return</function> może pojawić się w bloku instrukcji tylko wówczas, jeśli znajduje się on wewnątrz funkcji. W takim przypadku, oczywiście, <function>return</function> odnosi się do tej funkcji a nie do całego pliku. </simpara> </note> <para> <example> <title><function>include</function> i wyrażenie <function>return</function></title> <programlisting role="php"> <![CDATA[ return.php <?php $var = 'PHP'; return $var; ?> noreturn.php <?php $var = 'PHP'; ?> testreturns.php <?php $foo = include 'return.php'; echo $foo; // wyświetla 'PHP' $bar = include 'noreturn.php'; echo $bar; // wyświetla 1 ?> ]]> </programlisting> </example> </para> <simpara> Zmienna <literal>$bar</literal> ma wartość <literal>1</literal>, ponieważ wczytywanie pliku zakończyło się powodzeniem. Proszę zauważyć istotną różnicę pomiędzy powyższymi przykładami. Pierwszy używa instrukcji <function>return</function> wewnątrz wczytywanego pliku, natomiast drugi nie. Inne możliwości "wczytania" plików do zmiennych to <function>fopen</function>, <function>file</function> lub przez użycie <function>include</function> razem z <link linkend="ref.outcontrol">Funkcjami Kontroli Wyjścia<link>. </simpara> <simpara> Patrz także <function>require</function>, <function>require_once</function>, <function>include_once</function>, <function>readfile</function>, <function>virtual</function>, i <link linkend="ini.include-path">include_path</link>. </simpara> </sect1> <sect1 id="function.require-once"> <title><function>require_once</function></title> <para> Instrukcja <function>require_once</function> służy do wczytania i wykonania kodu z określonego pliku w trakcie wykonywania skryptu. Zachowanie jej jest identyczne z instrukcją <function>require</function> z jednym wyjątkiem, tzn. jeśli dany plik został już raz wczytany do tego skryptu, nie będzie wczytany ponownie. Więcej informacji na temat działania tej instrukcji w dokumentacji odnośnie <function>require</function>. </para> <para> <function>require_once</function> powinno być używane w przypadku, gdy ten sam plik mógłby zostać wczytany i wykonany wielokrotnie, ale ty chcesz mieć pewność, że zostanie wczytany dokładnie raz, aby uniknąć problemów z redefiniowaniem funkcji, nadpisywaniem zmiennych itp. </para> <para> Przykłady użycia <function>require_once</function> i <function>include_once</function> znajdują się w kodzie <ulink url="&url.php.pear;">PEAR</ulink> dołączonym do najnowszych dystrubucji kodu źródłowego PHP. </para> <note> <para> <function>require_once</function> dodano w PHP 4.0.1pl2 </para> </note> <para> Patrz także: <function>require</function>, <function>include</function>, <function>include_once</function>, <function>get_required_files</function>, <function>get_included_files</function>, <function>readfile</function>, i <function>virtual</function>. </para> </sect1> <sect1 id="function.include-once"> <title><function>include_once</function></title> <para> Instrukcja <function>include_once</function> służy do wczytania i wykonania kodu z określonego pliku w trakcie wykonywania skryptu. Działanie instrukcji podobne jest do <function>include</function>, z jednym wyjątkiem, tzn. jeśli dany plik został już raz do danego skryptu wczytany, nie będzie już wczytany ponownie. Wskazuje na to nazwa instrukcji: include_once znaczy wczytaj_raz. </para> <para> <function>include_once</function> powinno być stosowane w przypadkach, gdzie ten sam plik może być wczytany więcej niż raz w czasie wykonywania skryptu, ale ty chcesz mieć pewność że będzie wczytany tylko jeden raz, aby uniknąć problemów z redefiniowaniem funkcji, nadpisaniem wartości zmiennych, itp. </para> <para> Więcej przykładów wykorzystania <function>require_once</function> i <function>include_once</function> znajdziesz w kodzie <ulink url="&url.php.pear;">PEAR</ulink> dołączonym do najnowszych dystrybucji kodu źródłowego PHP. </para> <note> <para> <function>include_once</function> dodano w PHP 4.0.1pl2 </para> </note> <para> Patrz także <function>include</function>, <function>require</function>, <function>require_once</function>, <function>get_required_files</function>, <function>get_included_files</function>, <function>readfile</function>, i <function>virtual</function>. </para> </sect1> </chapter> <!-- Keep this comment at the end of the file Local variables: mode: sgml sgml-omittag:t sgml-shorttag:t sgml-minimize-attributes:nil sgml-always-quote-attributes:t sgml-indent-step:1 sgml-indent-data:t indent-tabs-mode:nil sgml-parent-document:nil sgml-default-dtd-file:"../../manual.ced" sgml-exposed-tags:nil sgml-local-catalogs:nil sgml-local-ecat-files:nil End: vim600: syn=xml fen fdm=syntax fdl=2 si vim: et tw=78 syn=sgml vi: ts=1 sw=1 -->