I am looking for a reason why in blade files (Laravel) code with mixed @php()
and @php ... @endphp
fails, and works fine with consistent usage of those codes across the file. I’ve just learned that the hard way but can’t find the reason.
Fails:
@php($foo = 'foo')
<h1>{{ $foo }}</h1>
@php
$bar = $foo . 'bar';
@endphp
@for($i = 1; $i<10; $i++)
<h2><b>{{ $i }}<b/>{{ $bar }}</h2>
@endfor
Works fine:
@php($foo = 'foo')
<h1>{{ $foo }}</h1>
@php($bar = $foo . 'bar');
@for($i = 1; $i<10; $i++)
<h2><b>{{ $i }}<b/>{{ $bar }}</h2>
@endfor
Also works fine:
@php
$foo = 'foo';
@endphp
<h1>{{ $foo }}</h1>
@php
$bar = $foo . 'bar';
@endphp
@for($i = 1; $i<10; $i++)
<h2><b>{{ $i }}<b/>{{ $bar }}</h2>
@endfor
An error
2
Answers
It seems to be a scoping issue (or whatever you want to call it) as I mentioned in the comments.
I did some testing in my own project.
Adding below code snippet in a view;
Results in the below, raw PHP output:
You can see why it fails, the
@php($foo = 'foo')
directive is seen as a starting PHP tag which does not end until the@endphp
directive after the$bar
variable initialization. That means that all the code between the@php($foo = 'foo')
and@endphp
directives is not seen as PHP code.Laravel also does not recommend the usage of the inline PHP directive anymore, as can be seen in this (quite recent) reply to someone with the same issue.
So, I recommend (as do they), to just use a regular PHP block as you did in your last example:
Update
As @apokryfos pointed out, the link referenced in the answer is actually not correct. It references another issue not related to the
@php()
directive. However, it does reference the Laravel core team member recommending not using anything other than the@php
and@endphp
directives, therefore I’m leaving it in.The issue in my view is the order of operations when processing
@php
blocks.The relevant source code will first store uncompiled blocks before it actually compiles anything. Uncompiled blocks seem to be
@php ... @endphp
and@verbatim ... @endverbatim
blocks. The code for@php
is:So in your code block, the process of trying to store code between a
@php ... @endphp
everything between@php($foo = 'foo')
and@endphp
will be matched (which includes the 2nd@php
tag) which will result in broken PHP code being stored.Reading the docs I can see that while the syntax
@php ... @endphp
is documented, the alternative syntax@php(...)
is not which makes me think that while the blade compiler implementation supports this syntax, it has not been documented (or not documented anymore) because it is problematic.