← Back to PHP Course | Chapter 14: Advanced PHP | Lesson 13 of 24

PHP 8 New Features

PHP 8 brought new tools that make code shorter and safer, like a new edition of a favorite game with handy extra moves. It adds neat helpers for common jobs that used to need extra work.
Syntax
php
str_contains($haystack, $needle);
str_starts_with($haystack, $prefix);
str_ends_with($haystack, $suffix);

$value = $object?->property?->method();   // nullsafe operator

The str_contains() function

str_contains() finally gave PHP a native, readable way to check for a substring -- before PHP 8, developers had to awkwardly check whether strpos() returned false, which was easy to get subtly wrong.

Example: The str_contains() function

php
<?php
// Check whether `!function_exists('str_contains')`
if (!function_exists('str_contains')) {
    // Define the function `str_contains` taking `$haystack`, `$needle`
    function str_contains($haystack, $needle) { return strpos($haystack, $needle) !== false; }
}
// Print a detailed dump (with types) of `str_contains("Hello World", "World")`
var_dump(str_contains("Hello World", "World"));
?>

The str_starts_with() and str_ends_with() functions

str_starts_with() and str_ends_with() cover the two other common substring checks natively, replacing brittle substr()-and-compare patterns that had shown up in PHP code for years.

Example: The str_starts_with() and str_ends_with() functions

php
<?php
// Check whether `!function_exists('str_starts_with')`
if (!function_exists('str_starts_with')) {
    // Define the function `str_starts_with` taking `$haystack`, `$needle`
    function str_starts_with($haystack, $needle) { return substr($haystack, 0, strlen($needle)) === $needle; }
}
// Check whether `!function_exists('str_ends_with')`
if (!function_exists('str_ends_with')) {
    // Define the function `str_ends_with` taking `$haystack`, `$needle`
    function str_ends_with($haystack, $needle) { return substr($haystack, -strlen($needle)) === $needle; }
}
// Print a detailed dump (with types) of `str_starts_with("Hello World", "Hello")`
var_dump(str_starts_with("Hello World", "Hello"));
// Print a detailed dump (with types) of `str_ends_with("Hello World", "World")`
var_dump(str_ends_with("Hello World", "World"));
?>

The Nullsafe Operator (?->)

The nullsafe operator (?->) short-circuits a chained call the moment any link in the chain is null, returning null immediately instead of throwing a fatal error -- a big readability win over nested isset() checks.

Example: The Nullsafe Operator (?->)

php
<?php
// PHP 8.0+ syntax
class Address { public $city = "Austin"; }
class User { public $address = null; }
$user = new User();
echo $user->address?->city ?? "No address set";
?>

Constructor Property Promotion

Constructor property promotion collapses the old pattern of declaring a property, adding it as a constructor parameter, and assigning it in the body into a single line per property, cutting a lot of boilerplate.

Example: Constructor Property Promotion

php
<?php
// PHP 8.0+ syntax
class Point {
    public function __construct(
        public float $x,
        public float $y
    ) {}
}
$p = new Point(1.5, 2.5);
echo "$p->x, $p->y";
?>

The match Expression

The match expression replaces switch in many cases: it uses strict comparison, requires no break statements, and directly returns a value, making common lookup-style logic far more compact and less error-prone.

Example: The match Expression

php
<?php
// Declare `$status`, set to `2`
$status = 2;
// Print `match($status) {` to the output
echo match($status) {
    1 => 'Pending',
    2 => 'Active',
    default => 'Unknown',
};
?>
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Using PHP 8 features such as match or str_contains on a server that runs an older PHP version.
  2. Using the nullsafe operator ?-> and expecting it to protect against undefined variables, when it only guards null objects.
  3. Using match without a default arm when no value matches, which throws UnhandledMatchError.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.