Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ potentially very difficult to debug due to dissimilar or unsupported package ver
- [PSR-0 support](#psr-0-support)
- [String values](#string-values)
- [Native functions and constants shadowing](#native-functions-shadowing)
- [Grouped constants whitelisting](#grouped-constants-whitelisting)
- [Composer](#composer)
- [Composer Plugins](#composer-plugins)
- [Contributing](#contributing)
Expand Down Expand Up @@ -543,6 +544,23 @@ is_array([]);
The situation is exactly the same for constants.


### Grouped constants whitelisting

When a grouped constant declaration like the following is given:

```php
const X = 'foo', Y = 'bar';
```

PHP-Scoper will not be able to whitelist either `X` or `Y`. The statement
above should be replaced by multiple constant statements:

```php
const X = 'foo';
const Y = 'bar';
```


### Composer

PHP-Scoper does not support prefixing the dumped Composer autoloader and autoloading files. This is why you have to
Expand Down
22 changes: 22 additions & 0 deletions specs/const/const-declaration.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<?php

const FOO_CONST = foo();
const X = 'x', Y = '';
define('BAR_CONST', foo());
define('Acme\BAR_CONST', foo());
define(FOO_CONST, foo());
Expand All @@ -37,6 +38,7 @@
namespace Humbug;

const FOO_CONST = \Humbug\foo();
const X = 'x', Y = '';
\define('BAR_CONST', \Humbug\foo());
\define('Humbug\\Acme\\BAR_CONST', \Humbug\foo());
\define(\Humbug\FOO_CONST, \Humbug\foo());
Expand All @@ -52,6 +54,7 @@
<?php

const FOO_CONST = foo();
const X = 'x', Y = '';
define('BAR_CONST', foo());
define('Acme\BAR_CONST', foo());
define(FOO_CONST, foo());
Expand All @@ -62,6 +65,7 @@

namespace {
const FOO_CONST = \foo();
const X = 'x', Y = '';
\define('BAR_CONST', \foo());
\define('Acme\\BAR_CONST', \foo());
\define(\FOO_CONST, \foo());
Expand All @@ -78,6 +82,7 @@
<?php

const FOO_CONST = foo();
const X = 'x', Y = '';
define('BAR_CONST', foo());
define('Acme\BAR_CONST', foo());
define(FOO_CONST, foo());
Expand All @@ -89,12 +94,23 @@
namespace Humbug;

\define('FOO_CONST', \Humbug\foo());
const X = 'x', Y = '';
\define('BAR_CONST', \Humbug\foo());
\define('Acme\\BAR_CONST', \Humbug\foo());
\define(\FOO_CONST, \Humbug\foo());
\define(\FOO_CONST, \Humbug\foo());
\define(\Acme\BAR_CONST, \Humbug\foo());

PHP
],

'Whitelisted grouped constants declaration in the global namespace' => [
'whitelist' => ['X'],
'payload' => <<<'PHP'
<?php

const X = 'x', Y = '';
----
PHP
],

Expand All @@ -105,6 +121,7 @@
namespace Acme;

const FOO_CONST = foo();
const X = 'x', Y = '';
define('BAR_CONST', foo());
define('Acme\BAR_CONST', foo());
define(FOO_CONST, foo());
Expand All @@ -116,6 +133,7 @@
namespace Humbug\Acme;

const FOO_CONST = foo();
const X = 'x', Y = '';
\define('BAR_CONST', foo());
\define('Humbug\\Acme\\BAR_CONST', foo());
\define(FOO_CONST, foo());
Expand All @@ -133,6 +151,7 @@
namespace Acme;

const FOO_CONST = foo();
const X = 'x', Y = '';
define('BAR_CONST', foo());
define('Acme\BAR_CONST', foo());
define(FOO_CONST, foo());
Expand All @@ -144,6 +163,7 @@
namespace Acme;

const FOO_CONST = foo();
const X = 'x', Y = '';
\define('BAR_CONST', foo());
\define('Acme\\BAR_CONST', foo());
\define(FOO_CONST, foo());
Expand All @@ -161,6 +181,7 @@
namespace Acme;

const FOO_CONST = foo();
const X = 'x', Y = '';
define('BAR_CONST', foo());
define('Acme\BAR_CONST', foo());
define(FOO_CONST, foo());
Expand All @@ -172,6 +193,7 @@
namespace Humbug\Acme;

const FOO_CONST = foo();
const X = 'x', Y = '';
\define('BAR_CONST', foo());
\define('Acme\\BAR_CONST', foo());
\define(FOO_CONST, foo());
Expand Down
54 changes: 31 additions & 23 deletions src/PhpParser/NodeVisitor/ConstStmtReplacer.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\NodeVisitorAbstract;
use UnexpectedValueException;
use function count;

/**
* Replaces const declaration by define.
Expand Down Expand Up @@ -62,31 +63,38 @@ public function enterNode(Node $node): Node
return $node;
}

// TODO: check this: when can Node\Stmt\Const_ be empty or have more than one constant
/** @var Node\Const_ $constant */
$constant = current($node->consts);
foreach ($node->consts as $constant) {
/** @var Node\Const_ $constant */
$resolvedConstantName = $this->nameResolver->resolveName(
new Name(
(string) $constant->name,
$node->getAttributes()
)
)->getName();

$resolvedConstantName = $this->nameResolver->resolveName(
new Name(
(string) $constant->name,
$node->getAttributes() // Take the parent node attribute since no "parent" attribute is recorded in
// Node\Const_
// TODO: check with nikic if this is expected
)
)->getName();
if (false === $this->whitelist->isClassWhitelisted((string) $resolvedConstantName)) {
continue;
}

if (false === $this->whitelist->isClassWhitelisted((string) $resolvedConstantName)) {
return $node;
if (count($node->consts) > 1) {
throw new UnexpectedValueException(
'Whitelisting a constant declared in a grouped constant statement (e.g. `const FOO = '
.'\'foo\', BAR = \'bar\'; is not supported. Consider breaking it down in multiple constant '
.'declaration statements'
);
}

return new Expression(
new FuncCall(
new FullyQualified('define'),
[
new String_((string) $resolvedConstantName),
$constant->value,
]
)
);
}

return new Expression(
new FuncCall(
new FullyQualified('define'),
[
new String_((string) $resolvedConstantName),
$constant->value,
]
)
);
return $node;
}
}
21 changes: 18 additions & 3 deletions tests/Scoper/PhpScoperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator;
use Symfony\Component\Finder\Finder;
use Throwable;
use UnexpectedValueException;
use function Humbug\PhpScoper\create_fake_patcher;
use function Humbug\PhpScoper\create_parser;
use function implode;
Expand Down Expand Up @@ -422,7 +423,7 @@ function (...$args) use (&$i): bool {
/**
* @dataProvider provideValidFiles
*/
public function test_can_scope_valid_files(string $spec, string $contents, string $prefix, Whitelist $whitelist, string $expected)
public function test_can_scope_valid_files(string $spec, string $contents, string $prefix, Whitelist $whitelist, ?string $expected)
{
$filePath = 'file.php';

Expand All @@ -448,7 +449,21 @@ public function test_can_scope_valid_files(string $spec, string $contents, strin
)
);

$actual = $this->scoper->scope($filePath, $contents, $prefix, $patchers, $whitelist);
try {
$actual = $this->scoper->scope($filePath, $contents, $prefix, $patchers, $whitelist);

if (null === $expected) {
$this->fail('Expected exception to be thrown.');
}
} catch (UnexpectedValueException $exception) {
if (null !== $expected) {
throw $exception;
}

$this->assertTrue(true);

return;
}

$formattedWhitelist = 0 === count($whitelist)
? '[]'
Expand Down Expand Up @@ -559,7 +574,7 @@ private function parseSpecFile(array $meta, $fixtureTitle, $fixtureSet): Generat
$fixtureSet['whitelist-global-constants'] ?? $meta['whitelist-global-constants'],
...($fixtureSet['whitelist'] ?? $meta['whitelist'])
),
$payloadParts[1], // Expected output
'' === $payloadParts[1] ? null : $payloadParts[1], // Expected output
];
}
}