marcosh
marcosh

Reputation: 9008

Mock exit() function in PHP

For a library I am writing I would like to be able to mock the exit PHP function.

I tried to use php-mock to provide a namespaced version of exit, something like

namespace MyNamespace;

function exit()
{
    // my mocked version of the function
}

But this creates problems to the parser, which throws the following ParseError: syntax error, unexpected 'exit' (T_EXIT), expecting '('.

Is there any other way to mock a built in function without incurring in parsing problems? Should I try to modify the AST with something like BetterReflection?

Upvotes: 4

Views: 1070

Answers (2)

Felipe Shi Wu
Felipe Shi Wu

Reputation: 11

Since PHP 8.1, Fibers have been introduced, and I was drafting an idea to use them to interrupt execution and handle it after the interruption without terminating the PHP process.

What I have in mind is to wrap the logic inside a Fiber like this:

<?php

function run(callable $operation): mixed
{
    $fiber = new \Fiber($operation);
    $suspended = $fiber->start();
    if ($suspended instanceof ExitException) {
        return $suspended;
    }

    return $fiber->getReturn();
}

function mockedExit(): void {
    \Fiber::suspend(new ExitException('exit'));
}

$response = run(static function () {
    // Some Logic
    if (true) {
        mockedExit();
    }
    // Continue Logic
    return 'SUCCESS';
});

if ($response === 'SUCCESS') {
    echo 200;
} else {
    echo 500;
}

class ExitException extends \Exception {}

What I'm proposing here is to suspend the execution using Fibers since they support full-stack functions. I can foresee some trade-offs, such as managing the complexity of nested Fibers, but I don't see any immediate concerns.

Upvotes: 0

marcosh
marcosh

Reputation: 9008

As per comments, I guess that mocking language constructs is not feasible.

To test exit() I ended up spawning other processes with exec and asserting on their output and exist status

Upvotes: 1

Related Questions