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

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:
protected function storePhpBlocks($value)
{
return preg_replace_callback('/(?<!@)@php(.*?)@endphp/s', function ($matches) {
return $this->storeRawBlock("<?php{$matches[1]}?>");
}, $value);
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With