• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

keradus / PHP-CS-Fixer / 22042339290

15 Feb 2026 08:14PM UTC coverage: 92.957% (-0.2%) from 93.171%
22042339290

push

github

keradus
test: check PHP env in CI jobs

29302 of 31522 relevant lines covered (92.96%)

44.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.0
/src/Linter/ProcessLinter.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of PHP CS Fixer.
7
 *
8
 * (c) Fabien Potencier <fabien@symfony.com>
9
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14

15
namespace PhpCsFixer\Linter;
16

17
use PhpCsFixer\FileReader;
18
use PhpCsFixer\FileRemoval;
19
use Symfony\Component\Filesystem\Exception\IOException;
20
use Symfony\Component\Process\PhpExecutableFinder;
21
use Symfony\Component\Process\Process;
22

23
/**
24
 * Handle PHP code linting using separated process of `php -l _file_`.
25
 *
26
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
27
 *
28
 * @internal
29
 *
30
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
31
 */
32
final class ProcessLinter implements LinterInterface
33
{
34
    private FileRemoval $fileRemoval;
35

36
    private ProcessLinterProcessBuilder $processBuilder;
37

38
    /**
39
     * Temporary file for code linting.
40
     */
41
    private ?string $temporaryFile = null;
42

43
    /**
44
     * @param null|string $executable PHP executable, null for autodetection
45
     */
46
    public function __construct(?string $executable = null)
47
    {
48
        if (null === $executable) {
9✔
49
            $executableFinder = new PhpExecutableFinder();
9✔
50
            $executable = $executableFinder->find(false);
9✔
51

52
            if (false === $executable) {
9✔
53
                throw new UnavailableLinterException('Cannot find PHP executable.');
×
54
            }
55

56
            if ('phpdbg' === \PHP_SAPI) {
9✔
57
                if (!str_contains($executable, 'phpdbg')) {
×
58
                    throw new UnavailableLinterException('Automatically found PHP executable is non-standard phpdbg. Could not find proper PHP executable.');
×
59
                }
60

61
                // automatically found executable is `phpdbg`, let us try to fallback to regular `php`
62
                $executable = str_replace('phpdbg', 'php', $executable);
×
63

64
                if (!is_executable($executable)) {
×
65
                    throw new UnavailableLinterException('Automatically found PHP executable is phpdbg. Could not find proper PHP executable.');
×
66
                }
67
            }
68
        }
69

70
        $this->processBuilder = new ProcessLinterProcessBuilder($executable);
9✔
71
        $this->fileRemoval = new FileRemoval();
9✔
72
    }
73

74
    public function __destruct()
75
    {
76
        if (null !== $this->temporaryFile) {
9✔
77
            $this->fileRemoval->delete($this->temporaryFile);
3✔
78
        }
79
    }
80

81
    /**
82
     * This class is not intended to be serialized,
83
     * and cannot be deserialized (see __wakeup method).
84
     */
85
    public function __serialize(): array
86
    {
87
        throw new \BadMethodCallException('Cannot serialize '.self::class);
1✔
88
    }
89

90
    /**
91
     * Disable the deserialization of the class to prevent attacker executing
92
     * code by leveraging the __destruct method.
93
     *
94
     * @param array<string, mixed> $data
95
     *
96
     * @see https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection
97
     */
98
    public function __unserialize(array $data): void
99
    {
100
        throw new \BadMethodCallException('Cannot unserialize '.self::class);
1✔
101
    }
102

103
    public function isAsync(): bool
104
    {
105
        return true;
1✔
106
    }
107

108
    public function lintFile(string $path): LintingResultInterface
109
    {
110
        return new ProcessLintingResult($this->createProcessForFile($path), $path);
4✔
111
    }
112

113
    public function lintSource(string $source): LintingResultInterface
114
    {
115
        return new ProcessLintingResult($this->createProcessForSource($source), $this->temporaryFile);
3✔
116
    }
117

118
    /**
119
     * @param string $path path to file
120
     */
121
    private function createProcessForFile(string $path): Process
122
    {
123
        // in case php://stdin
124
        if (!is_file($path)) {
7✔
125
            return $this->createProcessForSource(FileReader::createSingleton()->read($path));
×
126
        }
127

128
        $process = $this->processBuilder->build($path);
7✔
129
        $process->setTimeout(10);
7✔
130
        $process->start();
7✔
131

132
        return $process;
7✔
133
    }
134

135
    /**
136
     * Create process that lint PHP code.
137
     *
138
     * @param string $source code
139
     */
140
    private function createProcessForSource(string $source): Process
141
    {
142
        if (null === $this->temporaryFile) {
3✔
143
            $this->temporaryFile = tempnam(sys_get_temp_dir(), 'cs_fixer_tmp_');
3✔
144
            $this->fileRemoval->observe($this->temporaryFile);
3✔
145
        }
146

147
        if (false === @file_put_contents($this->temporaryFile, $source)) {
3✔
148
            throw new IOException(\sprintf('Failed to write file "%s".', $this->temporaryFile), 0, null, $this->temporaryFile);
×
149
        }
150

151
        return $this->createProcessForFile($this->temporaryFile);
3✔
152
    }
153
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc