advanced php language

PHP 8.5 Pipe Operator

The pipe operator |> passes the value on the left into the callable on the right. It is useful when a value moves through several small transformations and you want the code to read from top to bottom.

It does not replace functions, methods, or clear variable names. It gives you another way to express a pipeline when each step is already simple.

The Basic Shape

These two lines do the same thing:

PHP example
<?php

declare(strict_types=1);

$length = 'Hello World' |> strlen(...);
$sameLength = strlen('Hello World');

echo $length . PHP_EOL;
echo $sameLength . PHP_EOL;

// Prints:
// 11
// 11

The right side must be a callable that accepts the value from the left. First-class callables such as strlen(...), closures, arrow functions, and invokable objects can all be used.

Reading Transformations Left To Right

The pipe operator becomes useful when several transformations happen in sequence.

PHP example
<?php

declare(strict_types=1);

$title = ' PHP 8.5 Released ';

$slug = $title
    |> trim(...)
    |> strtolower(...)
    |> (fn (string $value): string => str_replace('.', '', $value))
    |> (fn (string $value): string => str_replace(' ', '-', $value));

echo $slug . PHP_EOL;

// Prints:
// php-85-released

Without the pipe operator, this would usually become nested function calls or several intermediate variables. Both are valid, but the pipeline makes the order of work obvious.

Adapting Arguments With Closures

Many PHP functions need more than one argument. The pipe operator passes one value, so use a closure when you need to provide the other arguments.

PHP example
<?php

declare(strict_types=1);

$summary = '  Senior PHP Engineer  ';

$result = $summary
    |> trim(...)
    |> (fn (string $value): string => str_replace('PHP', 'Laravel', $value))
    |> (fn (string $value): string => '[' . $value . ']');

echo $result . PHP_EOL;

// Prints:
// [Senior Laravel Engineer]

The closures are not noise here. They show exactly how the piped value is being adapted for functions that need extra context.

Object Methods In A Pipeline

Object methods can be used through first-class callable syntax.

PHP example
<?php

declare(strict_types=1);

final class TextCleaner
{
    public function collapseSpaces(string $value): string
    {
        return preg_replace('/\s+/', ' ', $value) ?? '';
    }
}

$cleaner = new TextCleaner();

$name = "  Ada\n   Lovelace  "
    |> trim(...)
    |> $cleaner->collapseSpaces(...);

echo $name . PHP_EOL;

// Prints:
// Ada Lovelace

This is useful when a service object owns a small transformation and you want to compose it with other transformations.

When Intermediate Variables Are Better

A pipeline is not automatically clearer. If a step deserves a name, use a variable.

PHP example
<?php

declare(strict_types=1);

function normaliseEmail(string $email): string
{
    return $email
        |> trim(...)
        |> strtolower(...);
}

$rawEmail = '  ADA@EXAMPLE.COM  ';
$normalisedEmail = normaliseEmail($rawEmail);
$domain = substr(strrchr($normalisedEmail, '@') ?: '', 1);

echo $normalisedEmail . PHP_EOL;
echo $domain . PHP_EOL;

// Prints:
// ada@example.com
// example.com

The extracted variable $normalisedEmail makes the later domain parsing easier to understand. Pipelines should remove clutter, not hide meaning.

Avoid Side-Effect Pipelines

The pipe operator works best with transformations that return a value. Be careful with steps that mutate state, write files, send emails, or log as their main purpose.

PHP example
<?php

declare(strict_types=1);

function trimName(string $name): string
{
    return trim($name);
}

function titleCaseName(string $name): string
{
    return ucwords(strtolower($name));
}

$displayName = '  ADA LOVELACE  '
    |> trimName(...)
    |> titleCaseName(...);

echo $displayName . PHP_EOL;

// Prints:
// Ada Lovelace

Small pure functions make good pipeline steps because each step is easy to test and review.

What You Should Be Able To Do

After this lesson, you should be able to read and write a simple |> pipeline, use first-class callables and closures on the right side, and decide when a named variable is clearer.

For junior PHP work, this matters because modern codebases often prefer readable data transformations. The professional judgement is knowing when a pipeline improves the code and when it becomes clever for its own sake.

Practice

Practice: Build A Slug Pipeline

Create a small PHP 8.5 example that turns a title into a URL slug using the pipe operator.

Task

Build a pipeline that:

  • trims the input title
  • lowercases it
  • removes apostrophes
  • replaces spaces with hyphens
  • collapses repeated hyphens
  • trims hyphens from the start and end

Use strict types. Put the expected output inside the PHP code block as printed lines or comments.

Afterward, add a short note explaining why some steps use closures instead of first-class callables.

Show solution

This solution uses first-class callables where the existing function already accepts one argument, and closures where the piped value needs extra arguments.

PHP example
<?php

declare(strict_types=1);

function slugify(string $title): string
{
    return $title
        |> trim(...)
        |> strtolower(...)
        |> (fn (string $value): string => str_replace("'", '', $value))
        |> (fn (string $value): string => str_replace(' ', '-', $value))
        |> (fn (string $value): string => preg_replace('/-+/', '-', $value) ?? '')
        |> (fn (string $value): string => trim($value, '-'));
}

echo slugify("  What's New In PHP 8.5  ") . PHP_EOL;
echo slugify('  PHP   Pipelines  ') . PHP_EOL;

// Prints:
// whats-new-in-php-8.5
// php-pipelines

trim(...) and strtolower(...) can be used directly because they already accept the piped string as their main argument. The str_replace(), preg_replace(), and final trim() steps use closures because they need extra arguments as well as the value coming through the pipeline.