Issues (224)

src/Console/Php/PhpSettingsHandler.php (3 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
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 KevinGH\Box\Console\Php;
16
17
use Composer\XdebugHandler\XdebugHandler;
18
use Fidry\FileSystem\FS;
19
use KevinGH\Box\Constants;
20
use KevinGH\Box\Phar\PharPhpSettings;
21
use Psr\Log\LoggerInterface;
22
use Webmozart\Assert\Assert;
23
use function getenv;
24
use function ini_get;
25
use function ini_set;
26
use function KevinGH\Box\format_size;
27
use function KevinGH\Box\memory_to_bytes;
28
use function sprintf;
29
use function trim;
30
use const PHP_EOL;
31
32
/**
33
 * @private
34
 */
35
final class PhpSettingsHandler extends XdebugHandler
36
{
37
    private readonly LoggerInterface $logger;
38
    private readonly bool $pharReadonly;
39
40
    public function __construct(LoggerInterface $logger)
41
    {
42
        parent::__construct('box');
43
44
        $this->setPersistent();
45
46
        $this->setLogger($logger);
47
        $this->logger = $logger;
0 ignored issues
show
The property logger is declared read-only in KevinGH\Box\Console\Php\PhpSettingsHandler.
Loading history...
48
49
        $this->pharReadonly = PharPhpSettings::isReadonly();
0 ignored issues
show
The property pharReadonly is declared read-only in KevinGH\Box\Console\Php\PhpSettingsHandler.
Loading history...
50
        $this->setPersistent();
51
    }
52
53
    public function check(): void
54
    {
55
        $this->bumpMemoryLimit();
56
57
        parent::check();
58
    }
59
60
    protected function requiresRestart(bool $default): bool
61
    {
62
        if ($this->pharReadonly) {
63
            $this->logger->debug('phar.readonly is enabled');
64
65
            return true;
66
        }
67
68
        $this->logger->debug('phar.readonly is disabled');
69
70
        return parent::requiresRestart($default);
71
    }
72
73
    protected function restart(array $command): void
74
    {
75
        // Disable phar.readonly if set
76
        $this->disablePharReadonly();
77
78
        parent::restart($command);
79
    }
80
81
    private function disablePharReadonly(): void
82
    {
83
        if (PharPhpSettings::isReadonly()) {
84
            Assert::notNull($this->tmpIni);
85
86
            FS::appendToFile($this->tmpIni, 'phar.readonly=0'.PHP_EOL);
87
88
            $this->logger->debug('Configured `phar.readonly=0`');
89
        }
90
    }
91
92
    /**
93
     * @see https://github.com/composer/composer/blob/34c371f5f23e25eb9aa54ccc65136cf50930612e/bin/composer#L20-L50
94
     */
95
    private function bumpMemoryLimit(): void
96
    {
97
        $userDefinedMemoryLimit = self::getUserDefinedMemoryLimit();
98
99
        $memoryLimit = trim(ini_get('memory_limit'));
100
        $memoryLimitInBytes = '-1' === $memoryLimit ? -1 : memory_to_bytes($memoryLimit);
101
102
        // Whether the memory limit should be dumped
103
        $bumpMemoryLimit = (
104
            null === $userDefinedMemoryLimit
105
            && -1 !== $memoryLimitInBytes
106
            && $memoryLimitInBytes < 1024 * 1024 * 512
107
        );
108
        // Whether the memory limit should be set to the user defined memory limit
109
        $setUserDefinedMemoryLimit = (
110
            null !== $userDefinedMemoryLimit
111
            && $memoryLimitInBytes !== $userDefinedMemoryLimit
112
        );
113
114
        if ($bumpMemoryLimit && false === $setUserDefinedMemoryLimit) {
115
            ini_set('memory_limit', '512M');
116
117
            $this->logger->debug(
118
                sprintf(
119
                    'Changed the memory limit from "%s" to "%s"',
120
                    format_size($memoryLimitInBytes, 0),
121
                    '512M',
122
                ),
123
            );
124
        } elseif ($setUserDefinedMemoryLimit) {
125
            ini_set('memory_limit', (string) $userDefinedMemoryLimit);
126
127
            $this->logger->debug(
128
                sprintf(
129
                    'Changed the memory limit from "%s" to %s="%s"',
130
                    format_size($memoryLimitInBytes, 0),
131
                    Constants::MEMORY_LIMIT,
132
                    format_size($userDefinedMemoryLimit, 0),
0 ignored issues
show
It seems like $userDefinedMemoryLimit can also be of type null; however, parameter $size of KevinGH\Box\format_size() does only seem to accept double|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

132
                    format_size(/** @scrutinizer ignore-type */ $userDefinedMemoryLimit, 0),
Loading history...
133
                ),
134
            );
135
        } else {
136
            $this->logger->debug(
137
                sprintf(
138
                    'Current memory limit: "%s"',
139
                    format_size($memoryLimitInBytes, 0),
140
                ),
141
            );
142
        }
143
    }
144
145
    private static function getUserDefinedMemoryLimit(): ?int
146
    {
147
        $memoryLimit = getenv(Constants::MEMORY_LIMIT);
148
149
        if (false === $memoryLimit) {
150
            $memoryLimitInBytes = null;
151
        } elseif ('-1' === $memoryLimit) {
152
            $memoryLimitInBytes = -1;
153
        } else {
154
            $memoryLimitInBytes = memory_to_bytes($memoryLimit);
155
        }
156
157
        return $memoryLimitInBytes;
158
    }
159
}
160