Repository: PHP-CS-Fixer/PHP-CS-Fixer (PHP)

Issue:
PSR-12 declare(strict_types=1) and mixed with HTML causes fatal error
## Bug report

<!--
  Before reporting a bug, make sure PHP CS Fixer is up-to-date.

  Check that the issue is NOT regarded to an applied rule by using the `-vvv` option (will list applied rules) on a minimal code snippet.
-->

### Description

<!--
  Please describe the problem.
-->

When using the code snippet from [PSR-12](https://www.php-fig.org/psr/psr-12/#3-declare-statements-namespace-and-import-statements) with the provided PSR-12 ruleset, the code breaks and causes a `Fatal error`.

The fixer can't handle the missing `;` in the first line (which is valid PHP syntax) and tries to use the "block mode" (see code examples below).

The `-vvv` indicates it's an issue with the `braces` rule but I'm not sure where else to report this issue.

### Runtime version

```
PHP CS Fixer 3.15.1 BoY42 by Fabien Potencier and Dariusz Ruminski.
PHP runtime: 7.4.33
````

### Used command

<!--
   Provide the command used to run PHP CS Fixer (run with `-vvv`).
-->

```
vendor/bin/php-cs-fixer fix src/Psr12/Issue29CorrectDeclareMixedWithHtml.php -vvv

PHP CS Fixer 3.15.1 BoY42 by Fabien Potencier and Dariusz Ruminski.
PHP runtime: 7.4.33
Loaded config default from "/Users/jwittorf/Sites/fh.psr12-linting/.php-cs-fixer.dist.php".
Using cache file ".php-cs-fixer.cache".
Paths from configuration file have been overridden by paths provided as command arguments.
F                                                                                                                                                                                                   1 / 1 (100%)
Legend: .-no changes, F-fixed, S-skipped (cached or empty file), I-invalid file syntax (file ignored), E-error
   1) src/Psr12/Issue29CorrectDeclareMixedWithHtml.php (braces)

Fixed 1 of 1 files in 0.003 seconds, 14.000 MB memory used
```

### Configuration file

<!--
   Provide content of configuration file you used (.php-cs-fixer[.dist].php).
-->

```php
<?php

$dirs = [
    "src",
    "src-alternative-b",
    "src-alternative-c",
    "src-alternative-vendor",
//    "src-not-parseable",
];
$finder = PhpCsFixer\Finder::create()->in($dirs);

$config = new PhpCsFixer\Config();
return $config->setFinder($finder);
```

### Code snippet that reproduces the problem

<!--
  Provide a minimal code snippet before running PHP CS Fixer. If relevant,
  also provide the expected output, the actual output and/or the error that
  occurred, if any.

  Please use markdown syntax for each code snippet, e.g.:

  ```php
  <?php
  $var = 'foo';
  ```
-->

#### Before

```php
<?php declare(strict_types=1) ?>
<!DOCTYPE html>
<html lang="de">
<head>
    <title>Issue 29: Correct declarations with mixed HTML</title>
</head>
<body>
<h1>
    <?php
    date_default_timezone_set('Europe/Berlin');
    echo "Es ist in Berlin " . date("H:i:s") . " Uhr. ";
    ?>
</h1>
</body>
</html>
```

#### After

Executing the file causes `PHP Fatal error: strict_types declaration must not use block mode on line 1`

```php
<?php declare(strict_types=1) {
    ;
} ?>
<!DOCTYPE html>
<html lang="de">
<head>
    <title>Issue 29: Correct declarations with mixed HTML</title>
</head>
<body>
<h1>
    <?php
    date_default_timezone_set('Europe/Berlin');
echo "Es ist in Berlin " . date("H:i:s") . " Uhr. ";
?>
</h1>
</body>
</html>
```


Discussion:
Hey. thanks for your report!

I understand this is not best outcome for you, but core team will not put effort to fix this issue - I will also close it now [but feel free to continue discussion with anyone interested]

The HTML support will be revoked in code as it was never supposed to be officially supported. If you mix PHP with any other language, we consider it as bad practice and encourage to separate your logic from your view, and if you need code-support in view like for templating, we suggest to use one of templating engines.

If you want to still rely on Fixer for HTML-mixed files, till it's officially dropped, and you want to have bug you noticed fixed, I do encourage you to run PR with the fix. It will be recognised and merged with same flow as any other ticket - the only difference is that the fix need to come from interested ppl [and not from the core team]

You may take a look at search feature looking for HTML keyword to get extra context.

Big thanks for understanding!
Thanks for taking your time to explain, I understand the issues and was just reporting this because I've stumbled upon this while comparing different linters for my Bachelor's Thesis.

Thanks to @kubawerlos for the quick PR, I can use this for my work. This will put the PHP CS Fixer in a better position inside of my ranking :)
Thanks for PR @kubawerlos ! already meregd

@jwittorf , if you will want to talk about anything regarding the project, feel free to poke me or others at gitter.im
> Thanks for PR @kubawerlos ! already meregd
> 
> @jwittorf , if you will want to talk about anything regarding the project, feel free to poke me or others at gitter.im

Thanks and shoutout to @kubawerlos!

I think I'm good for now and already got everything I needed from the online docs. You already helped me a few months back at gitter.im, but I'll be happy to accept the offer if I run into any other issues :)

I can already say so much: by your quick response and creating the pull request within only a few hours, you're covering about half a page in my paper 👍 



Patch:
diff --git a/src/Fixer/ControlStructure/ControlStructureBracesFixer.php b/src/Fixer/ControlStructure/ControlStructureBracesFixer.php
index 4ab3ce93fca..fc9ef57f1ae 100644
--- a/src/Fixer/ControlStructure/ControlStructureBracesFixer.php
+++ b/src/Fixer/ControlStructure/ControlStructureBracesFixer.php
@@ -79,7 +79,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
             $nextAfterParenthesisEndIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
             $tokenAfterParenthesis = $tokens[$nextAfterParenthesisEndIndex];
 
-            if ($tokenAfterParenthesis->equalsAny([';', '{', ':'])) {
+            if ($tokenAfterParenthesis->equalsAny([';', '{', ':', [T_CLOSE_TAG]])) {
                 continue;
             }
 


Test patch:
diff --git a/tests/Fixer/ControlStructure/ControlStructureBracesFixerTest.php b/tests/Fixer/ControlStructure/ControlStructureBracesFixerTest.php
index 3f44ebf61d2..28c9831015b 100644
--- a/tests/Fixer/ControlStructure/ControlStructureBracesFixerTest.php
+++ b/tests/Fixer/ControlStructure/ControlStructureBracesFixerTest.php
@@ -151,5 +151,9 @@ public static function provideFixCases(): iterable
             '<?php if ($foo) { switch ($foo): case 1: ?> foo <?php endswitch; } ?>',
             '<?php if ($foo) switch ($foo): case 1: ?> foo <?php endswitch; ?>',
         ];
+
+        yield 'declare followed by closing tag' => [
+            '<?php declare(strict_types=1) ?>',
+        ];
     }
 }