Как вернуть false из PHP скрипт изнутри класса/функции?

Как я могу сделать основной PHP скрипт return false внутри класса или функции?

Почему: это из-за встроенного веб-сервера:

Если PHP файл указан в командной строке при запуске веб-сервера, он рассматривается как "маршрутизатор" script. script запускается в начале каждого HTTP-запроса. Если этот script возвращает FALSE, запрашиваемый ресурс возвращается как есть.

из документации по встроенному веб-серверу PHP

Другими словами, вы возвращаете false в свой маршрутизатор script, чтобы встроенный веб-сервер мог обслуживать статические файлы. Пример из документации:

if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"])) {
    return false;    // serve the requested resource as-is.
} else { 
    echo "<p>Welcome</p>";
}

Дело в том, что я пытаюсь добавить это поведение в веб-фреймворк: я не хочу писать это в index.php. Я предпочел бы инкапсулировать эту логику в класс (промежуточное ПО), который остановит выполнение script, если php_sapi_name() == 'cli-server' и задан статический актив.

Однако я не знаю, как я могу сделать весь PHP script return false из класса или функции, поскольку, очевидно, return false вернется из текущего метода/функции/файла, а не из основной файл.

Есть ли способ достичь такого же поведения с помощью exit() например? Я понимаю, что даже не знаю, что означает return false в главном файле (это конкретный код выхода?).

Ответ 1

Необходимо, чтобы маршрутизатор вызывал метод класса, а затем, если метод возвращает false, вы возвращаете false из файла вашего маршрутизатора.

Конечно, это может стать головной болью. Существует всего лишь два способа достижения того, чего вы хотите достичь.

Однако существует более быстрый способ: вы можете злоупотреблять исключениями и создавать специализированное исключение для случая:

StaticFileException.php

<?php
class StaticFileException extends Exception {}

router.php

<?php
try {
    $c = new Controller();
    return $c->handleRequest();
} catch (StaticFileException $e) {
    return false;
}

Как только у вас будет такой код, просто throw new StaticFileException и все готово.

Ответ 2

Если метод в вашем классе обрабатывает статические активы с помощью exit, тогда решение может быть таким же простым, как замена exit на return false, а вызов вызывающего объекта этого метода просто возвращает метод в глобальной области.

Итак, если ваш класс выглядит примерно так...

class Router
{
    public function handleRequest($uri)
    {
        if (is_file($this->docRoot . $uri->path)) {
            exit; // static file found
        } else {
            // handle as normal route
        }
    }
}

Просто замените exit на return false...

            return false; // static file found

Тогда, если ваш index.php работает примерно так:

$router = new Router($docRoot);
$router->handleRequest($_SERVER['REQUEST_URI']);

Просто добавьте обратный infront метода handleRequest, например...

return $router->handleRequest($_SERVER['REQUEST_URI']);

Это должно иметь минимальные побочные эффекты для дизайна вашей инфраструктуры и, как видите, требует очень мало кода и рефакторинга, поскольку возврат из глобальной области script имеет только один побочный эффект в PHP (при этом он возвращает значение на вызов script т.е. если вы использовали include/require как выражение в присваивании). В вашем случае, если index.php является вызывающим script, тогда вам не о чем беспокоиться, просто добавив return infront этого метода.

Конечно, как только вы вернетесь, остальная часть script не будет продолжена, поэтому убедитесь, что это последнее утверждение в вашем index.php. Вы даже можете просто присвоить возвращаемое значение временному значению и вернуться позже, если вам понадобится логика....

$router = new Router($docRoot);
if ($router->handleRequest($_SERVER['REQUEST_URI'])) {
    /* if you need to do anything else here ... */
} else {
    return false; // otherwise you can return false for static here
}

В общем, я бы сказал, что вызов exit изнутри функции/метода почти никогда не нужен. Это делает ваш класс сложнее тестировать и отлаживать, и на самом деле не имеет никакого преимущества от альтернатив, таких как выброс исключения или просто возврат из метода, а также позволяющий вызывающему обработать сценарии сбоев грациозно.

Ответ 3

Невозможно играть с функцией register_shutdown_function или с параметром auto_append_file, чтобы справиться с этим? Не очень приятно, но, возможно, это может сделать эту работу.