25 / 01 / 2017 Developers

Co nowego w PHP7?

Zastanawialiście się co nowego pojawiło się wraz z nową wersją? Jeśli nie, to powinniście (zaparzyć kawę i ewentualnie) czytać dalej!

Szybkość

Jako że nie tak łatwo jest przygotować sensowne testy sprawdźmy co mówi na ten temat Internet (a podobno jest znacznie lepiej):

Zwóćcie uwagę, że wraz z wyższą wersją HHVM spada przewaga PHP 7

Według testów PHP 7 jest nawet 2 razy szybsza od poprzednich wersji – robi wrażenie.

Jeśli chcecie jak sami sprawdzić jak sprawuje się wasz serwer sprawdźcie:

Nowości

Wskazanie typów skalarnych & zwrócenie wartości o określonym typie

Od PHP 5 możemy wskazać jakiego obiektu oczekujemy w parametrze:

<?php
function method1(DateTime $myDateTimeObj)
{
  // do sth
}

W PHP 7 (wreszcie) się pojawiają wraz możliwością wymuszenia zwrócenia wartości określonego typu:

<?php
function add(int $a, int $b) : int
{
  return $a + $b;
}

var_dump(add(1000, 1)); // int(1001)
var_dump(add('1000', '1')); // int(1001)

Ale zaraz! Przecież w drugim wywałoaniu pojawiają się napisy! Oszukali nas?! Otóż PHP dość liberalnie podchodzi do sprawdzania typu:

10, 10e2, ‚100’, ‚100meEither’ (wszystkie zostaną potraktowane jako int (ostatni przypadek wyrzuci przy okazji ostrzeżenie)).

Jeśli chcecie by PHP gorliwie sprawdzał typy, trzeba posłużyć się taką oto dyrektywą:

<?php
declare(strict_types=1);

Co ważne musi być ona dołączona w pierwszej linii i działa tylko w obrębie wykonywanego pliku. Co to znaczy?

// my_mul.php
<?php
declare(strict_types=1);

function multiply(int $a, int $b) : int
{
  return $a * $b;
}


// use_mul.php
<?php

include('my_mul.php');
var_dump(multiply('10', 10)) // int(100)

ale

// use_mul_v2.php
<?php
declare(strict_types=1);

include('my_mul.php');
var_dump(multiply('10', 10)) // Uncaught TypeError: Argument 1 passed to multiply() must be of the type integer, string given

Więcej informacji: https://wiki.php.net/rfc/scalar_type_hints_v5 (RFC)

“Kosmiczny” operator <=>

Jak to działa?

echo 1 <=> 1; // 0 - dla równych wartości
echo 1 <=> 0; // 1 - jeśli prawa wartość jest większa od wartości po lewej
echo 0 <=> 1; // -1 - jeśli prawa wartość jest mniejsza od wartości po lewej

działa także dla napisów

echo "x" <=> "x"; // 0
echo "y" <=> "x"; // 1
echo "y" <=> "z"; // -1

jak również tablic i obiektów:

echo [] <=> []; // 0
echo [1, 2, 3] <=> [1, 2, 3]; // 0
echo [1, 2, 3] <=> [1, 2]; // 1
echo [1, 2, 4] <=> [1, 2, 3]; // 1
echo [1, 2] <=> [1, 2, 3]; // -1
echo [1, 2, 3] <=> [1, 2, 4]; // -1

$a = (object) ["field" => "abc"]; 
$b = (object) ["field" => "abc"]; 
echo $a <=> $b; // 0

$a = (object) ["other_field" => "cba"]; 
$b = (object) ["other_field" => "abc"]; 
echo $a <=> $b; // 1


$a = (object) ["one_another" => "abc"]; 
$b = (object) ["one_another" => "cba"]; 
echo $a <=> $b; // -1

Więcej informacji: https://wiki.php.net/rfc/combined-comparison-operator

Null Coalesce Operator?

Proste zastosowanie

$username = $user->getName() ?? 'nobody';

Odpowiednik

$username = ($user->getId() === NULL) ? 'nobody' : $user->getName()

$width = $imageData['width'] ?? 100;

Bardziej złożony przykład
Pokolei próbujemy pozyskać konfigurację ze zmiennej $_GET[‚config’] jeśli nie ma żadnej wartości próbujemy pozyskać informację z pola $this->config. Jeśli i tu nie znajdziemy żadnej wartości wykorzystujemy wartość static::$defaultConfig

$defaultConfig = $_GET['config'] ?? $this->config ?? static::$defaultConfig;

Klasy anonimowe

Gdy nie zawsze chcemy (chce -opłaca się nam) tworzyć niezwykle mało użyteczną klasę możemy posłużyć się klasą anonimową. Przykład z Symfony wzięty:

use Symfony\Component\Process\Process;
 
$process = new class extends Process {
  public function start()
{
    		// do sth
  }
};

zamiast

namespace My\Namespace\Process;
 
use Symfony\Component\Process\Process as Base;
 
class Process extends Base {
  public function start() {
    		// do sth
  }
}
 
$process = new \My\Namespace\Process\Process;

Czy to na pewno jest ładnie? A to nie jest!?

array_walk($arr, function($v, $k) {
  echo 'Key: '.$k.' value: '.$k;
});

Więcej informacji: https://wiki.php.net/rfc/anonymous_classes

Stała tablicowa via define()

Od wersji 5.6 tablice mogą być także stałymi:

<?php
const MY_ARRAY = [
  'hey',
  'it's',
  'an',
  'array!',
];

ale dopiero wersja 7 wprowadza możliwość definiowania takiej stałej przy pomocy funkcji define()

define()
<?php
define('MY_ARRAY', [
  'I'm',
  'an array',
  'too!',
]);

Grupowanie deklaracji

do PHP 5.6

<?php
use Framework\Component\ClassA;
use Framework\Component\ClassB as ClassC;
use Framework\Component\OtherComponent\ClassD

od PHP 7

<?php
use Framework\Component\{
 	ClassA,
 	ClassB as ClassC,
 	OtherComponent\ClassD
};

można używać też do funkcji i stałych

<?php
use Framework\Component\{
 	ClassA,
 	function OtherComponent\someFunction,
 	const OtherComponent\SOME_CONSTANT
};

 Łap błędy!

W PHP 5.x błędy [RECOVERABLE] FATAL ERROR powodowały zatrzymanie skryptu, a dlaczego by ich nie złapać? Od teraz można. Nowa hierarchii wyjątków:

interface Throwable
  |- Exception implements Throwable
    	|- ...
  |- Error implements Throwable
    	|- TypeError extends Error
    	|- ParseError extends Error
    	|- ArithmeticError extends Error
        	|- DivisionByZeroError extends ArithmeticError
    	|- AssertionError extends Error
        
<?php
$foo = new class() {
  public function bar()
  {
    		echo 'works';
  }
};

try {
  $foo->bar(); // works
  $foo->bar2(); // bar2 caused an error!
} catch (Error $e) {
  echo 'bar2 caused an error!';
}

Wyrażenia po nowemu

Szybkość nowej wersji wzięła się m. in. z wprowadzenia AST, co wpłynęło również na sposób interpretowania zapisanych wyrażeń:

Wyrażenie

Działanie w PHP 5

Działanie w PHP 7

$$foo[‚bar’][‚baz’]

${$foo[‚bar’][‚baz’]}

($$foo)[‚bar’][‚baz’]

$foo->$bar[‚baz’]

$foo->{$bar[‚baz’]}

($foo->$bar)[‚baz’]

$foo->$bar[‚baz’]()

$foo->{$bar[‚baz’]}()

($foo->$bar)[‚baz’]()

Foo::$bar[‚baz’]()

Foo::{$bar[‚baz’]}()

(Foo::$bar)[‚baz’]()

Więcej informacji: https://wiki.php.net/rfc/abstract_syntax_tree

A co żegnamy?

  • <% // php code %>
  • <script language=’php’> // php code </script>

Tak! tak też można było!

  • Wszystkie funkcje ereg_ (zdeprecjonowane już od wersji 5.3.0); zastąpione przez funkcje preg_
  • Wszystkie funkcnie mysql_ (zdeprecjonowane w wersji 5.5.0); zastąpione prze funkcje mysqli_ lub PDO
  • Funkcja split() (zdeprecjonowana od wersji 5.3.0); możliwe alternatywy preg_split(), explode(), str_split()
  • Wielokrotne użycie domyślnego wariantu (default) w wyrażeniu switch

 Ma ktoś użycie z życia wzięte?!

Statyczne odwołania do niestatycznych metod będą usunięte w przyszłości (co jest komunikowane odpowiednim ostrzeżeniem)

class foo()
{
  public function bar()
  {
    	echo 'regular method';
  }
}

foo::bar(); // Deprecated: Non-static method foo::bar() should not be called statically
        	// regular method

Konstruktory znane z PHP 4 również są oznaczone jako przestarzałe

class foo2()
{
  public function foo2()
  {
    	echo 'the constructor';
  }
} // Deprecated:  Methods with the same name as their class will not be constructors in a future version of PHP;

Więcej informacji: http://php.net/manual/en/migration70.deprecated.php

To oczywiście nie wszystkie zmiany (starałem się wybrać raczej te najciekawsze i te które moim zdaniem są przydatne). Jeśli jesteście ciekawi wszystkich zmian w stosunku do wersji 5.6 zajrzyjcie TU.

FacebookTwitterGoogle+LinkedIn
  • W „STAŁA TABLICOWA VIA DEFINE()”
    trzeba coś poprawić z tymi apostrofami – zapis ” ‚I’m’ ” nie jest zbyt poprawny w tym kontekście.