Medzi rokmi 2014 a 2015 bola vyvinutá nová hlavná verzia jazyka PHP, ktorá bola označená za PHP 7. Posledným dôležitým míľnikom bola verzia PHP 5.6. Verzia PHP 6 bola vypustená kvôli neúspechu unikódovej vetvy jazyka, ktorá nebola nakoniec dotiahnutá do konca. Keďže viacero zdrojov odkazovalo na túto vetvu ako na budúce PHP 6, vývojári sa rozhodli zvoliť radšej verziu PHP 7.
PHP
PHP je populárny skriptovací jazyk, ktorý sa používa na vývoj dynamických webových stránok. Odhaduje sa, že až 80 % dynamických stránok používa jazyk PHP. Domovskou stránkou PHP je php.net, ktorá obsahuje rozsiahlu dokumentáciu k jazyku. Na stránke zetcode.com/lang/php/ nájdete podrobný PHP tutoriál v rozhraní PHP CLI.
Inštalácia PHP
Zo stránky php.net/downloads.php si stiahneme zdrojové súbory najnovšej verzie PHP 7; my si stiahneme súbor php-7.0.4.tar.bz2
.
$ bunzip2 php-7.0.4.tar.bz2 $ tar -xf php-7.0.4.tar $ cd php-7.0.4/
Dekomprimujeme súbor a premiestnime sa do adresára php-7.0.4/
.
$ sudo apt-get install libreadline-dev $ sudo apt-get install libicu-dev
Potrebujeme doinštalovať tieto dva balíčky; prvý je určený na vybudovanie interaktívneho shellu, druhý je nevyhnutný na kompiláciu medzinárodných unikódových komponentov.
$ ./configure --with-readline --enable-intl
Spustíme script configure
s podporou modulov readline
a intl
.
$ make $ sudo make install
Skompilujeme a nainštalujeme PHP. Je možné, že bude treba doinštalovať ďalšie balíčky; napríklad libxml2-dev
.
$ php -a Interactive shell php > echo PHP_VERSION; 7.0.4
Po úspešnej inštalácii si spustíme interaktívny PHP shell príkazom php -a
. Konštanta PHP_VERSION
obsahuje verziu jazyka PHP.
Celočíselné delenie
Operátor delenia (/) vracia desatinné číslo. Nová funkcia intdiv()
vykonáva celočíselné delenie. Jej prvým parametrom je delenec, druhým je deliteľ.
<?php echo 7/3, "\n"; echo intdiv(7, 3), "\n"; ?>
Tento príklad vypíše hodnoty desatinného a celočíselného delenia čísiel 7 a 3.
$ php integer_division.php 2.3333333333333 2
Toto je výstup programu integer_division.php
.
Trojcestný operátor <=>
Nový trojcestný operátor (<=>), nazývaný aj kombinovaný porovnávací operátor, zjednodušuje písanie zreťazených porovnávacích úkonov. Operátor sa správa podobne ako funkcie strcmp()
alebo version_compare()
.
$a <=> $b
Tento výraz vracia –1 ak je $a
menšie ako $b
, 0 ak je $a
rovné $b
, a 1 ak je $a
väčšie ako $b
.
($a < $b) ? -1 : (($a > $b) ? 1 : 0)
Vyššie uvedený výraz je napísaný bez použitia trojcestného operátoru.
<?php echo 1 <=> 1; // 0 echo 1 <=> 2; // -1 echo 2 <=> 1; // 1 echo "\n"; echo "a" <=> "a"; // 0 echo "a" <=> "b"; // -1 echo "b" <=> "a"; // 1 echo "\n"; echo [] <=> []; // 0 echo [1, 2, 3] <=> [1, 2, 3]; // 0 echo [1, 2, 3] <=> []; // 1 echo [1, 2, 3] <=> [1, 2, 1]; // 1 echo [1, 2, 3] <=> [1, 2, 4]; // -1 echo "\n"; ?>
V príklade použijeme kombinovaný porovnávací operátor na čísla, reťazce, a polia.
echo 1 <=> 1; // 0
Čísla sú porovnávané podľa veľkosti.
echo "a" <=> "b"; // -1
Reťazce sú porovnávané lexikálne, to znamená podľa ich abecedného poradia.
echo [1, 2, 3] <=> [1, 2, 1]; // 1
V prípade polí sú porovnávané zodpovedajúce elementy poľa.
$ php spaceship_operator.php 0-11 0-11 0011-1
Toto je výstup skriptu spaceship_operator.php
.
Operátor ??
Operátor (??) umožňuje zjednodušiť kód v prípadoch, keď sa využíva ternárny operátor spolu s funkciou isset()
, čo je v PHP častá záležitosť. Operátor vracia svoj prvý operand ak existuje a nemá hodnotu null
; v opačnom prípade vracia druhý operand.
php > $mycolour = $colour ?? "blue"; php > echo $mycolour; blue
Keďže premenná $colour
nie je definovaná, operátor ??
vracia druhý operand.
php > $mycolour = isset($colour) ? $colour : "blue"; php > echo $mycolour; blue
V predchádzajúcich verziách PHP sa využívala funkcia isset()
, ktorá skúma existenciu premennej a zároveň či premenná nie je rovná null
.
Deklarácie skalárnych typov
Deklarácie skalárnych typov umožňujú typovú kontrolu parametrov funkcií. Vynútené môžu byť tieto dátové typy: string
, int
, float
, a bool
.
Kontrola dátových typov nie je aktívna automaticky, je potrebné ju zapnúť funkciou declare()
.
<?php // declare(strict_types=1); function add(int $a, int $b) { return $a + $b; } $r = add(4, 6); echo "$r\n"; $r = add("4", "6"); echo "$r\n"; ?>
Vo východzom režime vypíše skript 10 v oboch prípadoch. Ak zapneme striktný mód, skript sa ukončí chybovou hláškou: Fatal error: Uncaught TypeError: Argument 1 passed to add()
must be of the type integer, string given
.
Deklarácie návratových typov
Deklarácie návratových typov uvádzajú typ hodnoty, ktorá sa vracia funkciou. Vynútiť sa môžu rovnaké dátové typy, ako v prípade typových deklarácií argumentov.
<?php declare(strict_types=1); function add( $a, $b) : int { return $a + $b; } $r = add(4, 6.0); echo "$r\n"; ?>
Funkcia add()
deklaruje návratový typ ako int
. Funkcia však vracia desatinné číslo; preto sa skript končí chybovou hláškou: Fatal error: Uncaught TypeError:
Return value of add() must be of the type integer, float returned
.
Escape sekvencie unikódových kódových bodov
Nová syntax umožňuje písanie unikódových znakov pomocou kódových bodov v hexadecimálnej forme. (Kódové body sú numerické hodnoty, ktoré reprezentujú ľubovoľný znak, prípadne formátovanie znakov.)
<?php echo "\u{13C7}", "\n"; echo "\u{1307}", "\n"; ?>
Príklad vypíše čerokézske písmeno que a etiópsku slabiku jwa.
$ php unicode_codepoints.php Ꮗ ጇ
Toto je výstup skriptu unicode_codepoints.php
.
IntlChar trieda
Nová trieda IntlChar
modulu intl
ponúka viacero utilít pre získavanie informácií o unikódových znakoch.
<?php echo IntlChar::charName('Ꮗ'), "\n"; echo IntlChar::charName('ጇ'), "\n"; ?>
V príklade využívame funkciu IntlChar::charName()
na získanie mena uvedeného znaku.
$ php intlcharex.php CHEROKEE LETTER QUE ETHIOPIC SYLLABLE JWA
Toto je výstup skriptu intlcharex.php
.
Anonymné triedy
Anonymné triedy sú triedy, ktorým nebol pridelený názov. Sú praktické ak potrebujeme jednoduché, jednoúčelové objekty.
<?php $c = new class { public function say() { echo "This is an anonymous class\n"; } }; $c->say(); ?>
V príklade priradíme objekt premennej $c
. Objekt bol vytvorený z anonymnej triedy.
$ php anonymous_class.php This is an anonymous class
Toto je výstup skriptu anonymous_class.php
.
Očakávania
Očakávania, v angličtine expectations, sú rozšírením staršej funkcie assert()
, s ktorou sú spätne kompatibilné. (Anglické slová expect a assert majú podobný význam.) Očakávania umožňujú vytvárať výroky s nulovými nákladmi v produkčnom nasadení a vyvolať výnimky, ak tieto výroky zlyhajú.
Konfiguračné nastavenie zend.assertions
môže mať jednu z týchto troch hodnôt:
- 1 — vytvoriť a spustiť kód (vývojový mód)
- 0 — vytvoriť kód a preskočiť ho počas behu programu
- –1 — nevytvoriť žiadny kód (nulové náklady, produkčný mód)
Nastavenie assert.exception
určuje, či sa vyvolá výnimka ak výrok zlyhá. Toto nastavenie je normálne vypnuté kvôli spätnej kompatibilite s funkciou assert()
.
<?php abstract class Grades { const A = 0; const B = 1; const C = 2; const D = 3; const E = 4; const FX = 5; } const G = 6; //$grade = Grades::A; $grade = G; switch ($grade) { case Grades::A: echo "Outstanding\n"; break; case Grades::B: echo "Superior\n"; break; case Grades::C: echo "Good\n"; break; case Grades::D: echo "Satisfactory\n"; break; case Grades::E: echo "Low pass\n"; break; case Grades::FX: echo "Failure\n"; break; default: assert(false, "Unrecognized grade passed through switch: {$grade}"); } echo "code continues\n"; ?>
V príklade sme vytvorili systém vysokoškolských známok.
//$grade = Grades::A; $grade = G;
Nesprávna hodnota je zadaná premennej $grade
.
default: assert(false, "Unrecognized grade passed through switch: {$grade}");
Pridáme výrok do miesta, ku ktorému by sa program nemal dopracovať.
$ php expectations.php Warning: assert(): Unrecognized grade passed through switch: 6 failed in /home/janbodnar/prog/php7/expectations.php on line 44 code continues
Ak spustíme skript, dostaneme uvedené varovanie. Skript však pokračuje.
ini_set('assert.exception', 1);
Ak aktivujeme výnimky pomocou ini_set()
, skript sa ukončí s chybovou hláškou: Fatal error: Uncaught AssertionError:
Unrecognized suit passed through switch: 6
.
Parameter levels funkcie dirname()
Funkcia dirname()
vracia cestu rodičovského adresára. Parameter levels
stanovuje, koľko rodičovských adresárov máme preskočiť.
<?php echo dirname('/usr/local/bin').PHP_EOL; echo dirname('/usr/local/bin', 1).PHP_EOL; echo dirname('/usr/local/bin', 2).PHP_EOL; echo dirname('/usr/local/bin', 3).PHP_EOL; ?>
V tomto skripte si vyskúšame viaceré volania funkcie dirname()
s rôzne nastaveným parametrom levels
.
$ php dirlevels.php /usr/local /usr/local /usr /
Tu máme výstup skriptu dirlevels.php
.
Konštantné polia pomocou define()
Od verzie PHP 5.6 je možné definovať konštantné polia pomocou kľúčového slova const
. V PHP 7, konštantné pole je možné definovať aj pomocou funkcie define()
.
<?php const POSSIBLE_GRADES = ['A', 'B', 'C', 'D', 'E', 'FX']; define('ALLOWED_IMAGE_EXTENSIONS', ['jpg', 'jpeg', 'gif', 'png']); print_r(POSSIBLE_GRADES); print_r(ALLOWED_IMAGE_EXTENSIONS); ?>
V príklade definujeme dve konštantné polia; jedno pomocou const
, druhé pomocou define()
.
$ php array_constants.php Array ( [0] => A [1] => B [2] => C [3] => D [4] => E [5] => FX ) Array ( [0] => jpg [1] => jpeg [2] => gif [3] => png )
Toto je výstup skriptu array_constants.php
.
Nová syntax kľúčového slova use
Pomocou kľúčového slova use
môžme použiť viaceré deklarácie v jednej inštrukcii.
<?php namespace ZetCode; class Night { function say() { echo "This is Night class\n"; } } class Day { function say() { echo "This is Day class\n"; } } function f1() { echo "This is f1()\n"; } function f2() { echo "This is f2()\n"; } ?>
V súbore myfile.php
máme dve triedy a dve funkcie vnorené v mennom priestore ZetCode
.
<?php include 'myfile.php'; use ZetCode\{Day, Night}; use function ZetCode\{f1, f2}; $d = new Day(); $d->say(); $n = new Night(); $n->say(); f1(); f2(); ?>
V súbore usegroup.php
použijeme triedy a funkcie z menného priestoru ZetCode
namespace.
use ZetCode\{Day, Night}; use function ZetCode\{f1, f2};
Pomocou novej syntaxe kľúčového slova use
importujeme viaceré deklarácie v jednej inštrukcii.
use ZetCode\Day; use ZetCode\Night; use function ZetCode\f1; use function ZetCode\f2;
V predchádzajúcich verziách jazyka PHP bolo treba importovať triedy a funkcie po jednom.
$ php usegroup.php This is Day class This is Night class This is f1() This is f2()
Toto je výstup skriptu usegroup.php
.
Metóda Closure::call
V PHP 5.4 pribudla možnosť naviazať lexikálne uzávery (closures) do oblasti objektu. Tento proces je v PHP 7 zjednodušený pomocou metódy call()
.
<?php class Greeting { private $word = "Hello"; } $f = function($whom) { echo "$this->word $whom\n"; }; $obj = new Greeting(); $f->call($obj, 'Tom'); $f->call($obj, 'Jane'); ?>
Pomocou closure získame prístup k privátnej premennej $word
triedy Greeting
.
$ php closure_call.php Hello Tom Hello Jane
Toto je výstup skriptu closure_call.php
.
Výraz return v generátoroch
V PHP 7 môžme použiť kľúčové slovo return
pre návrat finálneho výrazu v generátore. Táto hodnota sa môže vytiahnuť pomocou metódy getReturn()
, ktorá sa môže volať až keď generátor ukončí posielanie hodnôt.
<?php srand(); function random_numbers($k) { for ($i=0; $i<$k; $i++) { $r = rand(1, 10); yield $r; } return -1; } $rns = random_numbers(10); foreach ($rns as $r) { echo "$r\n"; } echo $rns->getReturn() . PHP_EOL; ?>
Náš generátor vytvára náhodné čísla. Na konci iterácií, generátor vráti hodnotu –1.
$ php generator_return.php 7 5 6 7 1 1 9 6 5 8 -1
Toto je výstup skriptu generator_return.php
.
Delegácia generátoru pomocou yield from
Delegácia generátorov umožňuje poskytovať hodnoty z iných generátorov, Traversable
objektov, alebo polí pomocou yield from
. To vedie k čistejšiemu kódu a lepšej použiteľnosti kódu.
<?php function f1() { yield from f2(); yield "f1() 1"; yield "f1() 2"; yield from [3, 4]; yield "f1() 3"; yield "f1() end"; } function f2() { yield "f2() 1"; yield "f2() 2"; yield "f2() 3"; yield "f2() end"; } $f = f1(); foreach ($f as $val) { echo "$val\n"; } ?>
V príklade použijem hodnoty z poľa a iného generátoru.
function f1() { yield from f2(); ...
Tu použijeme hodnoty z generátoru f2()
.
yield from [3, 4];
Tu zas z dvojprvkového poľa.
$ php generator_delegation.php f2() 1 f2() 2 f2() 3 f2() end f1() 1 f1() 2 3 4 f1() 3 f1() end
Toto je výstup programu generator_delegation.php
.
Uniformovaná syntax premenných
Nová uniformovaná syntax premenných umožňuje také kombinovanie operátorov, ktoré v minulých verziách neboli možné. Nová syntax vždy vyhodnocuje premenné zľava doprava. V niektorých prípadoch dochádza k porušeniu spätnej kompatibility výrazov, kde sa využíva stará evaluácia.
<?php function e() { echo "This is e() \n"; }; function f() { echo "This is f() \n"; return e; }; function g() { echo "This is g()\n"; return f; }; g(); echo "***********\n"; g()(); echo "***********\n"; g()()(); ?>
V príklade použijeme g()()
a g()()()
, ktoré neboli možné v predchádzajúcich verziách PHP.
g();
Tu spustíme funkciu g()
.
g()();
V tomto prípade sa spustí funkcia g()
a funkcia vrátená z funkcie g()
.
g()()();
Je vykonaná funkcia g()
, funkcia vrátená z funkcie g()
, a funkcia vrátená z vrátenej funkcie g()
.
$ php uniform_variable_syntax.php This is g() *********** This is g() This is f() *********** This is g() This is f() This is e()
Toto je výstup skriptu uniform_variable_syntax.php
.
Ďalej si ukážeme ďalší príklad syntaxe, ktorá je možná vďaka novej, uniformovanej syntaxe premenných.
<?php class A { function f() { echo "f() of A\n"; } } class B { function g() { echo "g() of B\n"; return new A(); } } $b = new B(); $b->g()::f(); ?>
Výraz $b->g()::f()
vykoná metódu f()
triedy A
, navrátenej metódou g()
triedy B
.
$ php uniform_variable_syntax2.php g() of B f() of A
Toto je výstup skriptu uniform_variable_syntax2.php
.
Nakoniec si ukážeme príklad okamžite vyvolaného funkčného výrazu, ktorý je známy z jazyka JavaScript.
<?php $v = (function() { return 11 - 5; })(); echo "$v\n"; ?>
Ide o anonymnú funkciu, ktorá je vykonaná hneď potom, čo bola definovaná.
$ php uniform_variable_syntax3.php 6
Toto je výstup programu uniform_variable_syntax3.php
.
Zmeny vo výnimkách a chybách
V PHP 7 je volaná výnimka pri fatálnych a obnoviteľných chybách ( E_ERROR
a E_RECOVERABLE_ERROR
). V predchádzajúcich verziách PHP došlo ku zastaveniu skriptu. Tieto chyby sú inštanciou novej, separátnej triedy Error
. Niektoré chyby hádžu konkrétnejšie druhy výnimiek: TypeError
, ParseError
, ArithmeticError
, a AssertionError
Varovania (warnings) a upozornenia (notices) zostávajú nezmenené; iba fatálne chyby a obnoviteľné chyby vyvolávajú zatiaľ výnimky.
Rozhranie Throwable
bolo vytvorené na zjednotenie dvoch rôznych vetiev výnimiek: Exception
a Error
; v PHP 7 obe triedy implementujú Throwable
rozhranie.
<?php class A { public function say() { echo "This is class A\n"; } } try { $a = new A(); $a->say(); $a = null; $a->say(); } catch (Error $e) { echo "Error occured" . PHP_EOL; echo $e->getMessage() . PHP_EOL ; echo "File: " . $e->getFile() . PHP_EOL; echo "Line: " . $e->getLine(). PHP_EOL; } echo "Script continues\n"; ?>
V tomto príklade voláme metódy na nulovom objekte. Zachytíme výnimku a spracujeme ju. Skript ďalej pokračuje.
$ php null_error.php This is class A Error occured Call to a member function say() on null File: /home/janbodnar/prog/php7/null_error.php Line: 17
Toto je výstup skriptu null_error.php
.
DivisionByZeroError
pochádza z ArithmeticError
; je volaná v prípade ak pri funkcii intdiv()
a module operátore (%) je deliteľ 0. Operátor delenia () spôsobí naďalej varovanie Warning: Division by zero
. Tieto nezrovnalosti sú spôsobené návrhovými chybami v minulosti, ktoré sa postupne naprávajú.
<?php $a = 4; $b = 0; try { $c = intdiv($a , $b); } catch (DivisionByZeroError $e) { echo "Error occured\n"; echo $e->getMessage() . PHP_EOL ; echo "File: " . $e->getFile() . PHP_EOL; echo "Line: " . $e->getLine(). PHP_EOL; } echo "$c \n"; echo "Script continues\n"; ?>
V príklade zachytíme a reportujeme výnimku DivisionByZeroError
volanú z funkcie intdiv()
.
$ php arithmetic_error.php Error occured Division by zero File: /home/janbodnar/prog/php7/arithmetic_error.php Line: 8 Script continues
Toto je výstup skriptu arithmetic_error.php
.
Zdroje
Nasledovné zdroje boli použité pri písaní tohto článku:
V tomto článku sme prezentovali novinky jazyka PHP 7. Článok vyšiel v angličtine na autorovej webovej stránke.