Last active
April 28, 2021 06:45
-
-
Save E1101/b05e913e26bdf7fb6c01 to your computer and use it in GitHub Desktop.
PHP New Features
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
## -------------------------------------------------- | |
## PHP ^7.4 | |
## -------------------------------------------------- | |
## | |
# Typed properties | |
# | |
class User { | |
public int $id; | |
public string $name; | |
} | |
## | |
# Arrow functions | |
# | |
$factor = 10; | |
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]); | |
// $nums = array(10, 20, 30, 40); | |
## | |
# Null coalescing assignment operator | |
# | |
$array['key'] ??= computeDefault(); | |
// is roughly equivalent to | |
if (!isset($array['key'])) | |
$array['key'] = computeDefault(); | |
$value = $object->property ?? 'fallback if null'; | |
$value = $array['foo'] ?? "fallback if key doesn't exists"; | |
## | |
# Unpacking inside arrays | |
# | |
$parts = ['apple', 'pear']; | |
$fruits = ['banana', 'orange', ...$parts, 'watermelon']; | |
// ['banana', 'orange', 'apple', 'pear', 'watermelon']; | |
$a = [/* … */]; | |
$b = [/* … */]; | |
$mergedArray = [...$a, ...$b]; | |
## | |
# Allow exceptions from __toString() | |
# | |
## -------------------------------------------------- | |
## PHP ~7.0 | |
## -------------------------------------------------- | |
## | |
# Scalar type declarations | |
# | |
declare(strict_types=0); | |
function add(int $a, int $b) { | |
return $a + $b; | |
} | |
## | |
# Return type declarations | |
# | |
declare(strict_types=1); // strict type checking | |
function add(int $a, int $b): int { | |
return (string)($a + $b); | |
} | |
## | |
# Nullable types | |
# | |
function welcome(?string $name) { | |
echo $name; | |
} | |
welcome(); // error | |
welcome(null); // valid | |
function welcome($name): ?string | |
{ | |
return null; // valid | |
} | |
## | |
# Void return types | |
# | |
function A(): void { | |
// valid | |
} | |
function B(): void { | |
return; // valid | |
} | |
function C(): void { | |
return null; // invalid | |
} | |
## | |
# Class constant visibility modifiers | |
# | |
class Visibility | |
{ | |
// Constants without defined visibility | |
const THE_DEFAULT_PUBLIC_CONST = 'PHP'; | |
// Constants with defined visibility | |
private const THE_PRIVATE_CONST = 'PHP'; | |
protected const THE_PROTECTED_CONST = 'PHP'; | |
public const THE_PUBLIC_CONST = 'PHP'; | |
} | |
## | |
# Anonymous classes | |
# | |
$foo = new class { | |
public function foo() { | |
return "bar"; | |
} | |
}; | |
## | |
# Closure::call() | |
# | |
class Foo | |
{ | |
private $foo = 'bar'; | |
} | |
$getFooCallback = function() { | |
return $this->foo; | |
}; | |
//PHP5 style | |
$binding = $getFooCallback->bindTo(new Foo,'Foo'); | |
echo $binding().PHP_EOL; | |
//PHP7 style | |
echo $getFooCallback->call(new Foo).PHP_EOL; | |
## | |
# Generator delegation | |
# | |
function gen() | |
{ | |
yield 1; | |
yield 2; | |
yield from gen2(); // <= delegate from another generator | |
} | |
function gen2() | |
{ | |
yield 3; | |
yield 4; | |
} | |
foreach (gen() as $val) | |
{ | |
echo $val, PHP_EOL; | |
} | |
## | |
# Generator return expressions | |
# | |
$gen = (function() { | |
yield 1; | |
yield 2; | |
return 3; | |
})(); | |
foreach ($gen as $val) { | |
echo $val, PHP_EOL; | |
} | |
echo $gen->getReturn(), PHP_EOL; // <= return part | |
## | |
# Null coalesce operator | |
# | |
$array = ['foo'=>'bar']; | |
//PHP5 style | |
$message = isset($array['foo']) ? $array['foo'] : 'not set'; | |
echo $message.PHP_EOL; | |
//PHP7 style | |
$message = $array['foo'] ?? 'not set'; // <= null coalesce | |
echo $message.PHP_EOL; | |
// or chained | |
$bar = $foo ?? $baz ?? 'default'; | |
## | |
# Space ship operator | |
# | |
$array = [ | |
"1 <=> 1" => 1 <=> 1, // 0 when both values are equal | |
"1 <=> 2" => 1 <=> 2, // -1 when the left value is less than the right value | |
"2 <=> 1" => 2 <=> 1, // 1 if the left value is greater than the right value | |
]; | |
## | |
# Level support for the dirname() function | |
# | |
// would echo '/var/www/html/app/etc' | |
echo dirname('/var/www/html/app/etc/config.php'); | |
// would echo '/var/www/html/app' | |
echo dirname('/var/www/html/app/etc/config.php', 2); | |
## | |
# Constant arrays | |
# | |
// The class constant - using 'const' keyword | |
class Rift { | |
const APP = [ | |
'name' => 'Rift', | |
'edition' => 'Community', | |
'version' => '2.1.2', | |
'licence' => 'OSL' | |
]; | |
} | |
// The constant - using 'define' construct | |
define('APP', [ | |
'name' => 'Rift', | |
'edition' => 'Community', | |
'version' => '2.1.2', | |
'licence' => 'OSL' | |
]); | |
echo Rift::APP['version']; | |
echo APP['version']; | |
## | |
# Catching multiple exceptions types | |
# | |
try { | |
// ... | |
} | |
catch (\InvalidArgumentException $e) | |
{ | |
// ... | |
} | |
catch (Exception $e) | |
{ | |
// ... | |
} | |
finally | |
{ | |
// ... | |
} | |
try { | |
// ... | |
} | |
catch (\InvalidArgumentException | \LengthException $e) | |
{ | |
// ... | |
} | |
## | |
# Group Import Declarations | |
# | |
use Framework\Module\Foo; | |
use Framework\Module\Bar; | |
use Framework\Module\Baz; | |
//PHP7 style | |
use Framework\Module\{Foo, Bar, Baz}; | |
## | |
# Iterable pseudo-type | |
# | |
function import(iterable $users = null) | |
{ | |
// ... | |
} | |
function mix(): iterable { | |
return [ | |
'Welcome', | |
33, | |
4200.00 | |
]; | |
} | |
function numbers(): iterable { | |
for ($i = 0; $i <= 5; $i++) { | |
yield $i; | |
} | |
} | |
## | |
# Unicode Codepoint Escape Syntax | |
# | |
echo "\u{1F602}"; // outputs 😂‚ | |
## | |
# Allow trailing comma in function and method calls | |
# | |
foo('bar', 'baz',); | |
## | |
# Option to make json_encode and json_decode throw exceptions on errors | |
# | |
try { | |
json_decode("{", false, 512, JSON_THROW_ON_ERROR); | |
} | |
catch (\JsonException $exception) { | |
echo $exception->getMessage(); // echoes "Syntax error" | |
} | |
## | |
# Changes In list() | |
# | |
// References in list() | |
$arr = ['apple', 'orange']; | |
list($a, &$b) = $arr; | |
$b = 'banana'; | |
echo $arr[1]; | |
# array(3) { | |
# [0]=> string(5) "blue" | |
# [1]=> string(6) "yellow" | |
# } | |
list($colors[], $colors[]) = ['green', 'yellow']; | |
## | |
# Session options | |
# | |
// Php7 will accept options instead of from php.ini | |
session_start([ | |
'name' =>'THEAPP', | |
'cookie_lifetime' => 3600, | |
'cookie_httponly' => 1, | |
'lazy_write' => 1 | |
]); | |
## | |
# Introduced is_countable() function | |
# | |
is_countable($x); | |
## | |
# Array destructuring | |
# | |
$members = [ | |
[1, 'Seb'], | |
[2, 'Alex'], | |
]; | |
foreach ($members as [$id, $name]) { | |
// do stuff with $id and $name | |
} | |
$members = [ | |
['id' => 1, 'name'=> 'Seb', 'twitter' => '@sebdedeyne' ], | |
]; | |
foreach ($members as ['twitter' => $twitterHandle, 'name' => $firstName]) { | |
// do stuff with $twitterHandle and $firstName | |
} | |
## | |
# Context sensitive lexer | |
# | |
class ReportPool { | |
public function include(Report $report) { | |
// | |
} | |
public function list() { | |
// | |
} | |
public static function new(array $items) { | |
return new self($items); | |
} | |
} | |
class Customer { | |
const class = 'Retail'; // Fatal error | |
} | |
## | |
# Heredoc and Nowdoc syntax requirements are more relaxed | |
# | |
$foo = ['foo', 'bar', <<<EOT | |
baz | |
- hello world! -- | |
ahoy | |
EOT, 'qux', 'quux' | |
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
## -------------------------------------------------- | |
## PHP ^8.0 | |
## -------------------------------------------------- | |
## | |
# Constructor Property Promotion | |
# | |
class FormRenderer | |
{ | |
private User $currentUser; | |
public function __construct( | |
private ThemeSystem $theme, | |
private UserRepository $users, | |
private ModuleSystem $modules, | |
) { | |
$this->currentUser = $this->users->getActiveUser(); | |
} | |
public function renderForm(Form $form): string | |
{ | |
// ... | |
} | |
} | |
## | |
# Named Arguments | |
# | |
$numbers = [1, 2, 3, 4, 5, 6]; | |
$evens = array_filter($numbers, function($n){ | |
return $n % 2 === 0; | |
}); | |
$squares = array_map(array: $numbers, callback: function($n) { | |
return $n * $n; | |
}); | |
## | |
# Union Types | |
# | |
class SampleClass { | |
public int|float $number; | |
function setNumber(int|float $number) { | |
$this->number = $number; | |
} | |
function getNumber(): int|float { | |
return $this->number; | |
} | |
} | |
## | |
# Null-Safe Operator | |
# | |
$country = null; | |
if ($session !== null) { | |
$user = $session->user; | |
if ($user !== null) { | |
$address = $user->getAddress(); | |
if ($address !== null) { | |
$country = $address->country; | |
} | |
} | |
} | |
// php8.0 | |
$country = $session?->user?->getAddress()?->country; | |
## | |
# Trailing Comma | |
# | |
function hello($name, $age) { | |
echo "Hello $name"; | |
} | |
hello( | |
'Zura', | |
28, | |
); | |
## | |
# Match Expression | |
# | |
$statusCode = 400; | |
switch ($statusCode) { | |
case 200: | |
case 300: | |
$message = null; | |
break; | |
case 500: | |
$message = 'server error'; | |
break; | |
default: | |
$message = 'unknown status code'; | |
break; | |
} | |
// php8.0 | |
$message = match ($statusCode) { | |
200, | |
300 => null, | |
500 => 'server error', | |
default => 'unknown status code', | |
}; | |
## | |
# Attributes | |
# | |
#[Attribute] | |
class ProductSubscriber | |
{ | |
#[ | |
ListenTo( \app\attributes\Product::EVENT_CREATED ), | |
\app\attributes\SampleAttribute, | |
] | |
public function onProductCreated(ProductCreated $event) | |
{ /* … */ | |
} | |
#[ListenTo( \app\attributes\Product::EVENT_DELETED )] | |
public function onProductDeleted(ProductDeleted $event) | |
{ /* … */ | |
} | |
} | |
$reflectionClass = new ReflectionClass(ProductSubscriber::class); | |
$m = $reflectionClass->getMethod('onProductCreated'); | |
echo '<pre>'; | |
var_dump($m->getAttributes()[1]->getName()); | |
echo '</pre>'; | |
// All different variations of attributes | |
#[ClassAttribute] | |
#[AttributeWithScalarExpression(1 + 1)] | |
#[AttributeWithClassNameAndConstants(PDO::class, PHP_VERSION_ID)] | |
#[AttributeWithClassConstant(Http::POST)] | |
#[AttributeWithBitShift(4 >> 1, 4 << 1)] | |
class MyClass | |
{ | |
#[PropertyAttribute] | |
public int $foo; | |
#[ConstAttribute] | |
public const BAR = 1; | |
/** @return void */ | |
#[MethodAttribute] | |
/** @return void */ | |
public function doSomething(#[ArgumentAttribute] $bar): void | |
{ | |
$closure = #[ClosureAttribute] fn() => 1; | |
} | |
} | |
$object = new #[ObjectAttribute] class () { /* … */ | |
}; | |
#[FunctionAttribute] | |
function foo() | |
{ /* … */ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment