Overwrite laravel 5 helper function

2019-01-24 06:48发布

问题:

I'm using the response() helper very often and I just return the data with a message to the user. Now I have to include the http status code as well, but I don't want to change every response (which is likely bad anyway).

So I'm trying to overwrite the response() helper function by creating my own helpers.php within app/Http/helpers.php.

When I add it to my composer files, it does autoload the current helpers.php from the framework first and when I add it before the autload include in bootstrap/global.php I wont be able to use the app() and other Laravel functions.

How would I be able to solve this issue? I just want to include the status code as well in the response array.

回答1:

All Laravel helper functions written with this logic

if ( ! function_exists('response'))
{
    function response($content = '', $status = 200, array $headers = array())
    {
         // function body
    }
}

for first Laravel check is this function exists, if it exists, Laravel will not define this function again(otherwise it will throw fatal error). So if you will define your function before autoloader include vendor/laravel/framework/src/Illuminate/Foundation/helpers.php file, you can define your custom response function.

Unfortunately there is no way to say composer load first your autoload.files section, then laravel autoload.files. But you can do small hack ...

open bootstrap/autoload.php file and include your file before autoloader

// file with your custom helper functions
require __DIR__.'/../app/app/Http/helpers.php'; 
require __DIR__.'/../vendor/autoload.php';


回答2:

I'm not going to directly answer your question since I don't know if there's a solution (without changing Laravels helpers.php or renaming your function)

However there is a solution from the framework for this common use case. Response Macros

You can define a macro (this is done in a service provider)

Response::macro('foo', function($value){
    // do some stuff
    return Response::make($value);
});

And you can use it like this:

return response()->foo('bar');


回答3:

I've just had to do this in order to override the now() helper so I can control the apparent time when running tests. I followed the regular advice of creating app/Http/helpers.php and then adding it to bootstrap/autoload.php like so:

require __DIR__.'/../app/Http/helpers.php'; // added
require __DIR__.'/../vendor/autoload.php';

This usually works because as Marty says, all helpers are only defined if there's not an existing function with that name. So the two lines above load your custom helpers, then perform all vendor autoloading, which includes Laravel's helpers, and your already-defined function takes precedence.

But unfortunately, autoload.php doesn't seem to be used when testing with Behat, which is what I'm using. So I needed an alternative solution. Long story short, the only easy way to ensure that files get autoloaded before vendor files is by using the https://github.com/funkjedi/composer-include-files package. To quote from its readme:

In the past simply modifying bootstrap/autoload.php to include helpers was sufficient. However new versions of PHPUnit include the Composer Autoloader prior to executing the PHPUnit bootstrap file. Consequently this method of overriding helpers is no longer viable as it will trigger a fatal error when your bootstrap file is included.

So I installed this package using composer require funkjedi/composer-include-files and then added this to composer.json:

"extra": {
    "include_files": [
        "app/Http/helpers.php"
    ]
},

Once that's done, run composer dump-autoload to regenerate the autoload files. Now the overrides work both during regular app operation, and when running tests!