Passed
Pull Request — master (#415)
by Théo
02:20
created

PhpSettingsHandler::getUserDefinedMemoryLimit()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 13
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 0
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 Assert\Assertion;
18
use Composer\XdebugHandler\XdebugHandler;
19
use function getenv;
20
use function ini_get;
21
use function ini_set;
22
use const KevinGH\Box\BOX_MEMORY_LIMIT;
0 ignored issues
show
Bug introduced by
The constant KevinGH\Box\BOX_MEMORY_LIMIT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
23
use function KevinGH\Box\FileSystem\append_to_file;
24
use function KevinGH\Box\format_size;
25
use function KevinGH\Box\memory_to_bytes;
26
use const PHP_EOL;
27
use Psr\Log\LoggerInterface;
28
use function sprintf;
29
use function trim;
30
31
/**
32
 * @private
33
 */
34
final class PhpSettingsHandler extends XdebugHandler
35
{
36
    private $logger;
37
    private $pharReadonly;
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    public function __construct(LoggerInterface $logger)
43
    {
44
        parent::__construct('box', '--ansi');
45
46
        $this->setLogger($logger);
47
        $this->logger = $logger;
48
49
        $this->pharReadonly = '1' === ini_get('phar.readonly');
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    public function check()
56
    {
57
        $this->bumpMemoryLimit();
58
59
        return parent::check();
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::check() targeting Composer\XdebugHandler\XdebugHandler::check() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    protected function requiresRestart($isLoaded): bool
66
    {
67
        if ($this->pharReadonly) {
68
            $this->logger->debug('phar.readonly is enabled');
69
70
            return true;
71
        }
72
73
        $this->logger->debug('phar.readonly is disabled');
74
75
        return parent::requiresRestart($isLoaded);
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    protected function restart($command): void
82
    {
83
        // Disable phar.readonly if set
84
        $this->disablePharReadonly();
85
86
        parent::restart($command);
87
    }
88
89
    private function disablePharReadonly(): void
90
    {
91
        if (ini_get('phar.readonly')) {
92
            Assertion::notNull($this->tmpIni);
93
94
            append_to_file($this->tmpIni, 'phar.readonly=0'.PHP_EOL);
95
96
            $this->logger->debug('Configured `phar.readonly=0`');
97
        }
98
    }
99
100
    /**
101
     * @see https://github.com/composer/composer/blob/34c371f5f23e25eb9aa54ccc65136cf50930612e/bin/composer#L20-L50
102
     */
103
    private function bumpMemoryLimit(): void
104
    {
105
        $userDefinedMemoryLimit = self::getUserDefinedMemoryLimit();
106
107
        $memoryLimit = trim(ini_get('memory_limit'));
108
        $memoryLimitInBytes = '-1' === $memoryLimit ? -1 : memory_to_bytes($memoryLimit);
109
110
        // Whether or not the memory limit should be dumped
111
        $bumpMemoryLimit = (
112
            null === $userDefinedMemoryLimit
113
            && -1 !== $memoryLimitInBytes
114
            && $memoryLimitInBytes < 1024 * 1024 * 512
115
        );
116
        // Whether or not the memory limit should be set to the user defined memory limit
117
        $setUserDefinedMemoryLimit = (
118
            null !== $userDefinedMemoryLimit
119
            && $memoryLimitInBytes !== $userDefinedMemoryLimit
120
        );
121
122
        if ($bumpMemoryLimit && false === $setUserDefinedMemoryLimit) {
123
            ini_set('memory_limit', '512M');
124
125
            $this->logger->debug(
126
                sprintf(
127
                    'Changed the memory limit from "%s" to "%s"',
128
                    format_size($memoryLimitInBytes, 0),
129
                    '512M'
130
                )
131
            );
132
        } elseif ($setUserDefinedMemoryLimit) {
133
            ini_set('memory_limit', (string) $userDefinedMemoryLimit);
134
135
            $this->logger->debug(
136
                sprintf(
137
                    'Changed the memory limit from "%s" to %s="%s"',
138
                    format_size($memoryLimitInBytes, 0),
139
                    BOX_MEMORY_LIMIT,
140
                    format_size($userDefinedMemoryLimit, 0)
0 ignored issues
show
Bug introduced by
It seems like $userDefinedMemoryLimit can also be of type null; however, parameter $size of KevinGH\Box\format_size() does only seem to accept 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

140
                    format_size(/** @scrutinizer ignore-type */ $userDefinedMemoryLimit, 0)
Loading history...
141
                )
142
            );
143
        } else {
144
            $this->logger->debug(
145
                sprintf(
146
                    'Current memory limit: "%s"',
147
                    format_size($memoryLimitInBytes, 0)
148
                )
149
            );
150
        }
151
    }
152
153
    /**
154
     * @return null|int
155
     */
156
    private static function getUserDefinedMemoryLimit(): ?int
157
    {
158
        $memoryLimit = getenv(BOX_MEMORY_LIMIT);
159
160
        if (false === $memoryLimit) {
161
            $memoryLimitInBytes = null;
162
        } elseif ('-1' === $memoryLimit) {
163
            $memoryLimitInBytes = -1;
164
        } else {
165
            $memoryLimitInBytes = memory_to_bytes($memoryLimit);
166
        }
167
168
        return $memoryLimitInBytes;
169
    }
170
}
171