- Dynamic symbols
- Date symbols
- Heredoc values
- Callables
- String values
- Native functions and constants shadowing
- Composer Autoloader
- Composer Plugins
- PSR-0 Partial support
- Exposing/Excluding traits
- Exposing/Excluding enums
- Declaring a custom namespaced function
function_exists()
PHP-Scoper tries to prefix strings as well whenever possible. There will however be cases in which it will not be possible such as:
- strings in regexps, e.g.
/^Acme\\\\Foo/
- concatenated strings, e.g.:
$class = 'Symfony\\Component\\'.$name;
const X = 'Symfony\\Component' . '\\Yaml\\Ya_1';
You code may be using a convention for the date string formats which could be mistaken for classes, e.g.:
const ISO8601_BASIC = 'Ymd\THis\Z';
In this scenario, PHP-Scoper has no way to tell that string 'Ymd\THis\Z'
does
not refer to a symbol but is a date format. In this case, you will have to rely
on patchers. Note however that PHP-Scoper will be able to
handle some cases such as, see the date-spec.
If you consider the following code:
<?php
<<<PHP_HEREDOC
<?php
use Acme\Foo;
PHP_HEREDOC;
The content of PHP_HEREDOC
will not be prefixed. Some partial support could be
added in the future but is bound to be very limited due to the dynamic nature of
heredocs. If you consider the following for example:
<?php
<<<EOF
<?php
{$namespaceLine}
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
if (\\class_exists(\\Container{$hash}\\{$options['class']}::class, false)) {
// no-op
} elseif (!include __DIR__.'/Container{$hash}/{$options['class']}.php') {
touch(__DIR__.'/Container{$hash}.legacy');
return;
}
if (!\\class_exists({$options['class']}::class, false)) {
\\class_alias(\\Container{$hash}\\{$options['class']}::class, {$options['class']}::class, false);
}
return new \\Container{$hash}\\{$options['class']}(array(
'container.build_hash' => '$hash',
'container.build_id' => '$id',
'container.build_time' => $time,
), __DIR__.\\DIRECTORY_SEPARATOR.'Container{$hash}');
EOF;
It would be very hard to properly scope the relevant classes.
To fix such cases, you will need to resort to patchers.
If you consider the two following values:
['Acme\Foo', 'bar'];
'Acme\Foo::bar';
The classes used there will not be scoped. It should not be impossible to add support for it, but it is currently not supported. See #286.
To fix such cases, you will need to resort to patchers.
PHP-Scoper tries whenever possible to prefix strings as well:
class_exists('Acme\Foo');
// Will be prefixed into:
\class_exists('Humbug\Acme\Foo');
PHP-Scoper uses a regex to determine if the string is a class name that must be prefixed. But there is bound to have confusing cases. For example:
- If you have a plain string
'Acme\Foo'
which has nothing to do with a class, PHP-Parser will not be able to tell and will prefix it - Classes belonging to the global scope:
'Foo'
or'Acme_Foo'
, because there is no way to know if it is a class name or a random string except for a handful of methods such asclass_alias
,function_exists
, etc.
To fix such cases, you will need to resort to patchers.
In the following example:
<?php
namespace Foo;
is_array([]);
No use statement is used for the function is_array
. This means that PHP will
try to load the function \Foo\is_array
and if fails to do so will fallback
on \is_array
(note that PHP does so only for functions and constants, not
classes).
In order to bring some performance optimisation, the call will nonetheless be
prefixed in \is_array
. This will break your code if you were relying on
\Foo\is_array
instead. This however should be extremely rare, so if that
happens you have two solutions: use a patcher or simply remove
any ambiguity by making use of a use statement (which is unneeded outside of
the context of prefixing your code):
<?php
namespace Foo;
use function Foo\is_array;
is_array([]);
The situation is exactly the same for constants.
PHP-Scoper does not support prefixing the dumped Composer autoloader and autoloading files. This is why you have to manually dump the autoloader again after prefixing an application.
Note: when using Box, Box is able to take care of that step for you.
PHP-Scoper also can not handle Composers static file autoloaders. This is due to Composer loading files based on a hash which is generated from package name and relative file path. For a workaround see #298.
To fix such cases, you will need to resort to patchers.
Composer plugins are not supported. The issue is that for
Exposing symbols PHP-Scoper relies on the fact that you
should load the vendor/scoper-autoload.php
file instead of
vendor/autoload.php
to trigger the loading of the right classes with their
class aliases. However Composer does not do that and as a result interfaces such as
Composer\Plugin\Capability\Capable
are prefixed but the alias is not registered.
This cannot be changed easily so for now when you are using an isolated version
of Composer, you will need to use the --no-plugins
option.
As of now, given the following directory structure:
src/
JsonMapper.php
JsonMapper/
Exception.php
with the following configuration:
{
"autoload": {
"psr-0": {"JsonMapper": "src/"}
}
}
The autoloading will not work. Indeed, PHP-Scoper attempts to support PSR-0 by transforming it to PSR-4, i.e. in the case above:
{
"autoload": {
"psr-4": {"PhpScoperPrefix\\JsonMapper": "src/"}
}
}
If this works for the classes under src/JsonMapper/
, it will not for JsonMapper.php
.
There is currently no way to expose or exclude a trait. Since there is no aliasing mechanism for traits, it could be still possible by declaring a trait that extends the scoped trait, but this is currently not implemented.
There is currently no way to expose or exclude an enum. The problem being there is no way to alias one.
When PHP-Scoper encounters a call such as this one:
namespace App;
function_exists('NewApp\main');
That the string contained by function_exists
is a fully-qualified class name.
This is true however if function_exists()
is the native PHP one. However,
technically, if the function App\function_exists()
does exist, then the call
above would call App\function_exists()
and not function_exists()
.
This is a very unlikely scenario which is why PHP-Scoper will assume it is the PHP native one.
If, by any chance, this is a problem, you will have to fix it with patchers.