Getting started
PHP 7.0 Highlights
Scalar Type Declarations
function add(int $a, int $b): int {
return $a + $b;
}
add(1, 2); // 3
add(1.5, 2.5); // 3 (casted)
Null Coalescing
// Before PHP 7
$name = isset($_GET['name'])
? $_GET['name']
: 'Guest';
// PHP 7.0+
$name = $_GET['name'] ?? 'Guest';
Spaceship Operator
1 <=> 2; // -1
2 <=> 2; // 0
3 <=> 2; // 1
usort($arr, fn($a, $b) => $a <=> $b);
PHP 7.1 Highlights
Nullable Types
function getUser(?int $id): ?User {
if ($id === null) return null;
return User::find($id);
}
Void Return Type
function log(string $msg): void {
echo $msg;
// No return statement
}
Array Destructuring
$data = ['Alice', 30, 'Engineer'];
// Symmetric syntax
[$name, $age, $job] = $data;
PHP 7.4 Highlights
Typed Properties
class User {
public int $id;
public string $name;
private ?DateTime $created = null;
}
Arrow Functions
// Before PHP 7.4
$fn = function($x) {
return $x * 2;
};
// PHP 7.4+
$fn = fn($x) => $x * 2;
Null Coalescing Assignment
// Before PHP 7.4
$data['key'] = $data['key'] ?? 'default';
// PHP 7.4+
$data['key'] ??= 'default';
Type Declarations (7.0+)
Scalar Types
| Type | Description |
|---|---|
int |
Integer values |
float |
Floating point numbers |
string |
String values |
bool |
Boolean values |
Strict Types
<?php
declare(strict_types=1);
function sum(int $a, int $b): int {
return $a + $b;
}
sum(1, 2); // OK
sum(1.5, 2); // TypeError
Type Coercion (default)
<?php
// No declare statement
function sum(int $a, int $b): int {
return $a + $b;
}
sum(1, 2); // 3
sum(1.5, 2.8); // 3 (coerced)
Return Types
Basic Return Types
function getName(): string {
return 'John';
}
function getAge(): int {
return 30;
}
function isActive(): bool {
return true;
}
Array & Callable
function getItems(): array {
return [1, 2, 3];
}
function getCallback(): callable {
return function() { };
}
Class Types
function getUser(): User {
return new User();
}
function getDateTime(): DateTime {
return new DateTime();
}
Nullable Types (7.1+)
Nullable Parameters
function greet(?string $name): string {
return $name ?? 'Guest';
}
greet('Alice'); // "Alice"
greet(null); // "Guest"
Nullable Returns
function find(int $id): ?User {
$user = User::findById($id);
return $user ?: null;
}
$user = find(1); // User or null
Combined
function process(?array $data): ?string {
if ($data === null) return null;
return implode(',', $data);
}
Void Type (7.1+)
Basic Void
function log(string $msg): void {
file_put_contents('log.txt', $msg);
}
function redirect(string $url): void {
header("Location: $url");
exit;
}
Void Cannot Return
function invalid(): void {
return null; // Error!
}
function valid(): void {
return; // OK
}
Object Type (7.2+)
function setData(object $obj): object {
$obj->modified = true;
return $obj;
}
setData(new stdClass()); // OK
setData(new User()); // OK
setData([]); // TypeError
Iterable Type (7.1+)
function process(iterable $data): void {
foreach ($data as $item) {
echo $item;
}
}
process([1, 2, 3]); // OK
process(new ArrayIterator()); // OK
process('string'); // TypeError
Typed Properties (7.4+)
Basic Syntax
Property Types
class User {
public int $id;
public string $name;
public bool $active;
private float $balance;
protected array $roles;
}
Nullable Properties
class Post {
public ?string $title = null;
public ?User $author = null;
public ?DateTime $published;
}
Default Values
class Config {
public string $env = 'production';
public int $timeout = 30;
public array $options = [];
}
Class Types
class Article {
public User $author;
public DateTime $created;
private Category $category;
}
$article = new Article();
$article->author = new User(); // OK
$article->author = 'string'; // TypeError
Uninitialized State
Error on Access
class User {
public int $id;
public string $name;
}
$user = new User();
echo $user->id; // Error: Uninitialized
Must Initialize
class User {
public int $id;
public function __construct(int $id) {
$this->id = $id; // Required
}
}
Visibility Modifiers
class Product {
public string $name;
protected float $cost;
private int $stock;
public static string $category;
}
Operators
Null Coalescing (??) (7.0+)
Basic Usage
$name = $_GET['name'] ?? 'Guest';
$age = $user->age ?? 0;
$color = $config['color'] ?? 'blue';
Chaining
$value = $a ?? $b ?? $c ?? 'default';
Before PHP 7
// Ternary
$name = isset($_GET['name'])
? $_GET['name']
: 'Guest';
// Short ternary
$name = $_GET['name'] ?: 'Guest';
Null Coalescing Assignment (??=) (7.4+)
Assignment Shorthand
// Before 7.4
$data['key'] = $data['key'] ?? 'default';
// PHP 7.4+
$data['key'] ??= 'default';
Real-World Examples
$_GET['page'] ??= 1;
$config['timeout'] ??= 30;
$cache[$key] ??= expensive_operation();
Difference from ||=
$value = 0;
$value ??= 10; // 0 (not null)
$value = $value ?: 10; // 10 (falsy)
Spaceship (<=>) (7.0+)
Three-Way Comparison
$a <=> $b;
// Returns:
// -1 if $a < $b
// 0 if $a == $b
// 1 if $a > $b
Sorting
$numbers = [3, 1, 4, 1, 5];
usort($numbers, fn($a, $b) => $a <=> $b);
// [1, 1, 3, 4, 5]
// Descending
usort($numbers, fn($a, $b) => $b <=> $a);
String Comparison
'a' <=> 'b'; // -1
'z' <=> 'a'; // 1
'x' <=> 'x'; // 0
$names = ['Zoe', 'Alice', 'Bob'];
usort($names, fn($a, $b) => $a <=> $b);
// ['Alice', 'Bob', 'Zoe']
Multi-Field Sorting
usort($users, function($a, $b) {
return [$a->last, $a->first]
<=> [$b->last, $b->first];
});
Arrow Functions (7.4+)
Basic Syntax
Short Syntax
// Before 7.4
$fn = function($x) {
return $x * 2;
};
// PHP 7.4+
$fn = fn($x) => $x * 2;
Array Functions
$numbers = [1, 2, 3, 4, 5];
$doubled = array_map(
fn($n) => $n * 2,
$numbers
);
$filtered = array_filter(
$numbers,
fn($n) => $n > 2
);
Automatic Capture
By-Value Capture
$multiplier = 3;
// Before 7.4
$fn = function($x) use ($multiplier) {
return $x * $multiplier;
};
// PHP 7.4+
$fn = fn($x) => $x * $multiplier;
Multiple Variables
$min = 10;
$max = 100;
$validate = fn($x) => $x >= $min && $x <= $max;
Single Expression
Implicit Return
$square = fn($x) => $x * $x;
$greet = fn($name) => "Hello, $name!";
$sum = fn($a, $b) => $a + $b;
Cannot Use Statements
// Invalid
$fn = fn($x) => {
$result = $x * 2;
return $result;
};
// Valid - use closure
$fn = function($x) {
$result = $x * 2;
return $result;
};
Type Declarations
$typed = fn(int $x): int => $x * 2;
$nullable = fn(?string $s): string =>
$s ?? 'default';
$complex = fn(User $u): ?string =>
$u->getName();
Real-World Examples
Sorting
usort($users, fn($a, $b) =>
$a->getName() <=> $b->getName()
);
Filtering
$adults = array_filter(
$people,
fn($p) => $p->age >= 18
);
Mapping
$names = array_map(
fn($user) => $user->name,
$users
);
Reduce
$total = array_reduce(
$items,
fn($carry, $item) => $carry + $item->price,
0
);
Array Features
Array Destructuring (7.1+)
Symmetric Syntax
$data = ['Alice', 30, 'Engineer'];
// PHP 7.1+
[$name, $age, $job] = $data;
// Still valid
list($name, $age, $job) = $data;
Skipping Elements
[$name, , $job] = ['Alice', 30, 'Engineer'];
// $name = 'Alice', $job = 'Engineer'
Nested Arrays
$data = ['Alice', [30, 'Engineer']];
[$name, [$age, $job]] = $data;
Keys in List (7.1+)
Associative Arrays
$user = [
'name' => 'Alice',
'age' => 30,
'job' => 'Engineer'
];
['name' => $name, 'age' => $age] = $user;
Mixed Keys
$data = ['id' => 1, 'Alice', 'email' => 'a@ex.com'];
['id' => $id, $name, 'email' => $email] = $data;
Foreach Destructuring
List Syntax
$users = [
['Alice', 30],
['Bob', 25],
];
foreach ($users as [$name, $age]) {
echo "$name is $age years old\n";
}
Keyed Destructuring
$users = [
['name' => 'Alice', 'age' => 30],
['name' => 'Bob', 'age' => 25],
];
foreach ($users as ['name' => $n, 'age' => $a]) {
echo "$n is $a years old\n";
}
References in Destructuring (7.3+)
$array = [1, 2, 3];
[$a, &$b] = $array;
$b = 10;
// $array is now [1, 10, 3]
Array Unpacking (7.4+)
Spread Operator
$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$merged = [...$arr1, ...$arr2];
// [1, 2, 3, 4, 5, 6]
With Keys
$defaults = ['a' => 1, 'b' => 2];
$custom = ['b' => 3, 'c' => 4];
$config = [...$defaults, ...$custom];
// ['a' => 1, 'b' => 3, 'c' => 4]
Before 7.4
$merged = array_merge($arr1, $arr2);
Class Features
Anonymous Classes (7.0+)
Basic Syntax
$logger = new class {
public function log($msg) {
echo $msg;
}
};
$logger->log('Hello');
With Constructor
$util = new class($dep) {
private $dependency;
public function __construct($dep) {
$this->dependency = $dep;
}
public function doSomething() {
return $this->dependency->process();
}
};
Implementing Interfaces
$handler = new class implements Handler {
public function handle($request) {
// Implementation
}
};
Extending Classes
$custom = new class extends BaseClass {
public function customMethod() {
return parent::baseMethod() . ' extended';
}
};
Class Constant Visibility (7.1+)
Visibility Modifiers
class Config {
public const PUBLIC_KEY = 'public';
protected const PROTECTED_KEY = 'protected';
private const PRIVATE_KEY = 'private';
}
echo Config::PUBLIC_KEY; // OK
echo Config::PRIVATE_KEY; // Error
Inheritance
class Base {
protected const VALUE = 10;
}
class Child extends Base {
public function getValue() {
return self::VALUE; // OK
}
}
echo Child::VALUE; // Error (protected)
Covariance & Contravariance (7.4+)
Return Type Covariance
interface Factory {
public function create(): object;
}
class UserFactory implements Factory {
// More specific return type
public function create(): User {
return new User();
}
}
Parameter Type Contravariance
interface Validator {
public function validate(User $user): bool;
}
class AdminValidator implements Validator {
// More general parameter type
public function validate(object $obj): bool {
return $obj instanceof User &&
$obj->isAdmin();
}
}
Exception Handling
Throwable Interface (7.0+)
Hierarchy
interface Throwable {
// Base interface
}
class Error implements Throwable {
// Internal errors
}
class Exception implements Throwable {
// User exceptions
}
Catching All
try {
// Code
} catch (Throwable $e) {
// Catches Error AND Exception
}
Error Hierarchy (7.0+)
Error
├── ArithmeticError
│ └── DivisionByZeroError
├── AssertionError
├── ParseError
└── TypeError
Catching Errors
try {
$result = 1 / 0;
} catch (DivisionByZeroError $e) {
echo "Cannot divide by zero";
}
try {
require 'invalid.php';
} catch (ParseError $e) {
echo "Parse error: " . $e->getMessage();
}
Multi-Catch (7.1+)
Single Handler
try {
// Code
} catch (IOException | NetworkException $e) {
log($e);
}
Multiple Handlers
try {
// Code
} catch (ValidationException | InvalidInputException $e) {
return response()->json(['error' => $e->getMessage()], 400);
} catch (NotFoundException $e) {
return response()->json(['error' => 'Not found'], 404);
} catch (Exception $e) {
return response()->json(['error' => 'Server error'], 500);
}
Syntax Improvements
Group Use Declarations (7.0+)
Before PHP 7
use Framework\Component\ClassA;
use Framework\Component\ClassB;
use Framework\Component\ClassC;
PHP 7.0+
use Framework\Component\{
ClassA,
ClassB,
ClassC
};
Mixed Types
use Framework\Component\{
ClassA,
ClassB,
function helper,
const CONFIG
};
Heredoc/Nowdoc (7.3+)
Flexible Indentation
// Before 7.3 - must be at column 0
$html = <<<HTML
<div>
<p>Content</p>
</div>
HTML;
// PHP 7.3+ - can indent
$html = <<<HTML
<div>
<p>Content</p>
</div>
HTML;
Trailing Comma
$sql = <<<SQL
SELECT *
FROM users
WHERE active = 1
SQL;
Trailing Commas (7.2-7.3)
Function Calls (7.3+)
$result = myFunction(
$arg1,
$arg2,
$arg3, // Trailing comma OK
);
Arrays (Always)
$data = [
'name' => 'Alice',
'age' => 30,
'job' => 'Engineer', // Always OK
];
Not in Declarations
// Still invalid
function test(
$arg1,
$arg2, // Error!
) {
}
Numeric Literal Separator (7.4+)
Readability
$million = 1_000_000;
$billion = 1_000_000_000;
$pi = 3.141_592_653_589;
$binary = 0b0101_1111;
$hex = 0xFF_EC_DE_5E;
Ignored in Value
1_000 == 1000; // true
1_2_3 == 123; // true
Generators
Generator Return (7.0+)
Return Value
function count_to($max) {
for ($i = 1; $i <= $max; $i++) {
yield $i;
}
return $max;
}
$gen = count_to(5);
foreach ($gen as $num) {
echo $num; // 1, 2, 3, 4, 5
}
echo $gen->getReturn(); // 5
Combined Results
function process() {
$sum = 0;
for ($i = 1; $i <= 10; $i++) {
yield $i;
$sum += $i;
}
return $sum;
}
Generator Delegation (7.0+)
Yield From
function gen1() {
yield 1;
yield 2;
}
function gen2() {
yield 3;
yield 4;
}
function combined() {
yield from gen1();
yield from gen2();
}
// Outputs: 1, 2, 3, 4
foreach (combined() as $num) {
echo $num;
}
Array Delegation
function numbers() {
yield from [1, 2, 3];
yield from range(4, 6);
}
Password Hashing
Argon2 Support (7.2+)
Argon2i (7.2+)
$hash = password_hash(
'secret',
PASSWORD_ARGON2I
);
password_verify('secret', $hash); // true
Argon2id (7.3+)
$hash = password_hash(
'secret',
PASSWORD_ARGON2ID,
['memory_cost' => 2048, 'time_cost' => 4, 'threads' => 3]
);
Custom Options
$options = [
'memory_cost' => 1024, // KiB
'time_cost' => 2,
'threads' => 2,
];
$hash = password_hash(
'password',
PASSWORD_ARGON2ID,
$options
);
Migration Guide
PHP 5 to 7 Changes
Type Hints
// PHP 5
function add($a, $b) {
return $a + $b;
}
// PHP 7
function add(int $a, int $b): int {
return $a + $b;
}
Error Handling
// PHP 5
try {
// Code
} catch (Exception $e) {
// Only catches Exception
}
// PHP 7
try {
// Code
} catch (Throwable $e) {
// Catches Error AND Exception
}
Null Handling
// PHP 5
$name = isset($user['name']) ? $user['name'] : 'Guest';
// PHP 7.0
$name = $user['name'] ?? 'Guest';
// PHP 7.4
$config['key'] ??= 'default';
Common Gotchas
Strict Types
<?php
declare(strict_types=1); // File-level
function test(int $x) { }
test('10'); // TypeError in strict mode
Uninitialized Properties
class User {
public int $id; // Must initialize!
}
$user = new User();
echo $user->id; // Error: Uninitialized
Void Returns
function log($msg): void {
echo $msg;
return null; // Error!
}
Arrow Function Limitations
// Cannot use statements
$fn = fn($x) => { // Error!
$y = $x * 2;
return $y;
};
// Use closure instead
$fn = function($x) {
$y = $x * 2;
return $y;
};
Performance Improvements
PHP 7.0 vs PHP 5.6
Speed Improvements
- 2x faster execution
- 50% less memory usage
- Better opcode caching
Benchmarks
# WordPress (requests/sec)
PHP 5.6: 49
PHP 7.0: 97 (+98%)
# Drupal (requests/sec)
PHP 5.6: 18
PHP 7.0: 35 (+94%)
Optimization Tips
Use Type Declarations
// Slower
function process($data) {
return count($data);
}
// Faster
function process(array $data): int {
return count($data);
}
Preload (7.4+)
// php.ini
opcache.preload=/path/to/preload.php
// preload.php
<?php
opcache_compile_file('app/User.php');
opcache_compile_file('app/Post.php');
Also see
- PHP 7.0 Release - Official PHP 7.0 release notes
- PHP 7.1 Release - Official PHP 7.1 release notes
- PHP 7.2 Release - Official PHP 7.2 release notes
- PHP 7.3 Release - Official PHP 7.3 release notes
- PHP 7.4 Release - Official PHP 7.4 release notes
- PHP Manual - Migration guides for all PHP 7 versions
- GitHub Issue #102 - Original feature request