TomasVotruba / bladestan

PHPStan analysis for Blade templates
https://tomasvotruba.com/blog/introducing-bladestan-phpstan-analysis-of-blade-templates/
MIT License
280 stars 13 forks source link

Syntax error, unexpected T_VARIABLE, expecting ';' #68

Open montchr opened 1 year ago

montchr commented 1 year ago

Not sure exactly what's causing this error, but I can update the title if we come to a more specific description of the issue.

When I install bladestan and run phpstan for the first time, I see the following error:

 ------ ---------------------------------------------------------------
  Line   app/View/Components/EntityList.php
 ------ ---------------------------------------------------------------
  17     Syntax error, unexpected T_VARIABLE, expecting ';' on line 17
 ------ ---------------------------------------------------------------

There are no other reported errors.

From some of the other issue descriptions in this repo, I gather that the line number corresponds to the template, not the controller? I saw that removing a blank line in the template caused an equal change in line numbering in the error report (was L18, now is L17).

Here is the relevant context, including both the template and its corresponding Component class:

❯ rg --context=5 EntityListLayout::GRID
resources/views/components/entity-list/index.blade.php
12-
13-  <div @class([
14-      'entity-list__items',
15-      "is-layout-$layout->value",
16-      'flex',
17:      'gap-4' => $layout === EntityListLayout::GRID,
18-      'flex-col gap-y-8' => $layout === EntityListLayout::STREAM,
19-  ])>
20-    @foreach ($entities as $entity)
21-      <div class="gap-4">
22-        <x-dynamic-component

app/View/Components/EntityList.php
14-{
15-    public function __construct(
16-        /** @var CoreObject[] */
17-        public array $entities,
18-        public ?string $title = null,
19:        public EntityListLayout $layout = EntityListLayout::GRID,
20-    ) {}
21-
22-    public function render()
23-    {
24-        return view('components.entity-list.index');

Other notes:

AJenbo commented 1 year ago

This is most often cause by non-terminated lined PHP statements in the template. See https://github.com/TomasVotruba/bladestan/issues/57 for details. When you get a syntax error like this the line number is in relation to the compiled php, not the blade template, so not very useful.

If you post the full template I can maybe spot the issue, unless it's in an included component.

montchr commented 1 year ago

Here's the full template, with a couple changes from what I posted earlier (still the same results):

@php
  $itemComponent = sprintf('entity-list.%s.item', $layout->value);
@endphp

<section {{ $attributes->class(['entity-list', 'flex flex-col']) }}>
  @if ($title)
    <x-section-title class='entity-list__title'>
      {{ $title }}
    </x-section-title>
  @endif

  <div @class([
      'entity-list__items',
      sprintf('is-layout-%s', $layout->value),
      'flex',
      'gap-4' => $layout === \App\View\Support\EntityListLayout::GRID,
      'flex-col gap-y-8' =>
          $layout === \App\View\Support\EntityListLayout::STREAM,
  ])>
    @foreach ($entities as $entity)
      <div class="gap-4">
        <x-dynamic-component
          :component="$itemComponent"
          :$entity
        />
      </div>
    @endforeach

  </div>
</section>

I've looked through the entire project for non-terminated statements in any template, but found none. I assume that the standalone @php() directive is exempt?

AJenbo commented 1 year ago

I assume that the standalone @php() directive is exempt?

No, that is exactly where this issue normally arises.

They are normally allowed in PHP but to analyze all of the code Bladestan collects them all in to a single script.

Edit: I'm not seeing any issues in the file you posted.

montchr commented 1 year ago

Hmm… even after eliminating @php() entirely and verifying that each statement ends in a semicolon, I still get the same error.

Is there any way I could see more detailed output to trace the exact code output that causes the issue?

More ripgrep output, also double-checked in phpstorm in case my regex is bad:

❯ rg  --multiline --multiline-dotall --glob 'resources/views/**/*.blade.php' '(@php.*?@endphp|@php\(.*?\))'
resources/views/layouts/sections/sidebar.blade.php
1:@php
2:  dynamic_sidebar('sidebar-primary');
3:@endphp

resources/views/search.blade.php
2:@php use App\View\Support\EntityListLayout; @endphp

resources/views/partials/site-navigation.blade.php
35:          @php
36:            $isLinkable = $item->url !== '' && $item->url !== '#';
37:          @endphp
192:                @php
193:                  $isLinkable = $item->url !== '' && $item->url !== '#';
194:                @endphp

resources/views/components/header/index.blade.php
1:@php
2:  use App\Support\AspectRatio;
3:  use App\Support\ImageSize;
4:@endphp

resources/views/page.blade.php
5:    @php
6:      the_post();
7:    @endphp

resources/views/project/content.blade.php
1:@php
2:  $reports = $project->reports();
3:@endphp

resources/views/components/entity-list/grid/item.blade.php
1:@php
2:  use App\Support\AspectRatio;
3:  use App\Support\ImageSize;
4:@endphp

resources/views/components/entity-list/wall/item.blade.php
1:@php use App\Support\ImageSize; @endphp

resources/views/components/entity-list/index.blade.php
1:@php
2:  $itemComponent = sprintf('entity-list.%s.item', $layout->value);
3:@endphp

resources/views/topic/content.blade.php
1:@php use App\View\Support\EntityListLayout; @endphp

resources/views/front-page.blade.php
2:@php
3:  $podcast_info_url = 'https://whyy.org/programs/stop-and-frisk-revisit-or-resist/';
4:@endphp

resources/views/components/entity-meta.blade.php
1:@php
2:  $authorName = $author?->name();
3:  $authorUrl = $author?->permalink();
4:
5:  $displayFormat = get_option('date_format');
6:  $published = $published->setTimezone(wp_timezone_string());
7:@endphp

resources/views/index.blade.php
16:      @php
17:        the_post();
18:      @endphp

resources/views/components/entity-list/stream/item.blade.php
1:@php
2:  use App\Support\AspectRatio;
3:  use App\Support\ImageSize;
4:@endphp
montchr commented 1 year ago

I guess, also: do you know of any other problematic directives / bad practices to watch out for?

Edit: for example, might these attributes count as non-terminated statements?

  <x-header
    :title="$report->title()"
    :image="$report->image()"
  >
AJenbo commented 1 year ago

resources/views/topic/content.blade.php @php use App\View\Support\EntityListLayout; @endphp

If this is a partial then you can't have use statements in it as it would result in things like:

@foreach([1])
    @include('topic.content')
}
<?php

foreach ([1] as $a) {
    use App\View\Support\EntityListLayout;
}

Thought I would have expected a different error if this was the issue. See https://github.com/TomasVotruba/bladestan/issues/58

AJenbo commented 1 year ago

I guess, also: do you know of any other problematic directives / bad practices to watch out for?

I documented the issues i found here: https://github.com/TomasVotruba/bladestan/issues/created_by/AJenbo

Edit: for example, might these attributes count as non-terminated statements?

  <x-header
    :title="$report->title()"
    :image="$report->image()"
  >

I don't belive that would be an issue.

AJenbo commented 1 year ago

Is there any way I could see more detailed output to trace the exact code output that causes the issue?

I would suggest analyzing one file at a time, enable debugging and in BladeToPHPCompiler around line 160 echo out the compiled php so you can see what it is analyzing, then you can search for the faulty line in your templates locate the cause of the issue that way.

https://github.com/TomasVotruba/bladestan/blob/256b84c054a900359dbca94d5d94a36f150c98b9/src/Compiler/BladeToPHPCompiler.php#L160

vendor/bin/phpstan analyze --error-format=blade --level 0 --debug app/Http/Controllers/HomeController.php

AJenbo commented 1 year ago

If that still doesn't give you a clear result then try removing 50% of the template until it parses succesfuld, the recover 25% and continue until you find the offending line. (bisecting the files)