Merge module.xp and autoload.php
Opened this issue · 7 comments
Scope of Change
This RFC suggests merging the special file module.xp
into autoload.php created for Composer loading purposes.
Rationale
- Consistent autoloading whether Composer is used or not; less I/O for the case it is.
- Syntax-checkable module initialization code
- Removed confusion with
.xp
source code from XP Compiler (phase 2) - Near zero cost for runtime module reflection (once libraries include module definitions)
Functionality
Current situation
Typical autoload.php file:
<?php namespace xp;
\lang\ClassLoader::registerPath(__DIR__);
An example module.xp:
<?php namespace com\example;
module xp-forge/example {
public function initialize() {
echo "Loaded module ", $this->name(), "\n";
}
}
Implementation
Code inside autoload.php
<?php namespace com\example;
use lang\ClassLoader;
ClassLoader::registerPath(__DIR__, false,'xp-forge/patterns', [
'initialize' => function() {
echo '(autoload.php) Loaded module ', $this->name(), "\n";
}
]);
Loading
- During composer loading,
autoload.php
is loaded viaautoload -> files
from composer.json - During XP bootstrapping,
autoload.php
would be discovered when registering a path. If a module definition is existant, nomodule.xp
file would be checked for.
Phases
- XP9.0. No BC breaks exist. You can start using the new layout alongside the old one.
- XP10.0. The file module.xp is deprecated, code needs to be migrated to the new layout
See also Transition below.
Security considerations
n/a
Speed impact
Slightly slower for the non-Composer case, since autoload.php files weren't being loaded.
Dependencies
None.
Related documents
Transition
This describes the various filesystem layouts and where module definitions are loaded from.
TL;DR:
If you don't use modules, no need for any action. If you do:
- If your library requires compatibility with XP < 9.0, use the BC module layout
- Otherwise use the new module layout only providing autoload.php
Basic Layout
Contains src/main/php/autoload.php
XP8.1 | XP8.1 + Composer | XP9.0 (+Composer) | XP10.0 (+Composer) | |
---|---|---|---|---|
Files loaded | (none) | autoload | autoload | autoload |
Module definition | (none) | (none) | (none) | (none) |
Classic module layout
Contains src/main/php/autoload.php and src/main/php/module.xp
XP8.1 | XP8.1 + Composer | XP9.0 (+Composer) | XP10.0 (+Composer) | |
---|---|---|---|---|
Files loaded | module | autoload, module | autoload, module | autoload |
Module definition | module | module | module | (none) |
New module layout
Contains src/main/php/autoload.php which defines $module.
XP8.1 | XP8.1 + Composer | XP9.0 (+Composer) | XP10.0 (+Composer) | |
---|---|---|---|---|
Files loaded | (none) | autoload | autoload | autoload |
Module definition | (none) | (none) | autoload | autoload |
BC module layout
Contains src/main/php/autoload.php which defines $module and src/main/php/module.xp for BC reasons. Note you need to maintain the module code twice in both files!
XP8.1 | XP8.1 + Composer | XP9.0 (+Composer) | XP10.0 (+Composer) | |
---|---|---|---|---|
Files loaded | module | autoload, module | autoload | autoload |
Module definition | module | module | autoload | autoload |
Example of transition to new functionality:
diff --git a/src/main/php/autoload.php b/src/main/php/autoload.php
index 832c1dd..89375e3 100755
--- a/src/main/php/autoload.php
+++ b/src/main/php/autoload.php
@@ -1,3 +1,18 @@
-<?php namespace xp;
+<?php namespace xp\compiler;
-\lang\ClassLoader::registerPath(__DIR__);
\ No newline at end of file
+use lang\ClassLoader;
+use lang\reflect\Package;
+
+define('MODIFIER_PACKAGE', 2048);
+define('MODIFIER_INLINE', 4096);
+define('MODIFIER_NATIVE', 8192);
+define('DETAIL_PROPERTY', 0);
+
+ClassLoader::registerPath(__DIR__, false, 'xp-framework/compiler', [
+
+ /** @return void */
+ 'initialize' => function() {
+ Syntax::registerAll(Package::forName('xp.compiler.syntax')->getPackages());
+ ClassLoader::registerLoader(JitClassLoader::instanceFor(realpath('.')), true);
+ }
+]);
For phase 2, the xp -v
output could be changed to show modules instead of class path entries:
$ git diff
diff --git a/src/main/php/xp/runtime/Version.class.php b/src/main/php/xp/runtime/Version.class.php
index c210000..7d950b1 100755
--- a/src/main/php/xp/runtime/Version.class.php
+++ b/src/main/php/xp/runtime/Version.class.php
@@ -1,6 +1,7 @@
<?php namespace xp\runtime;
use util\cmd\Console;
+use lang\reflect\Module;
/**
* Displays XP version and runtime information
@@ -43,15 +44,15 @@ class Version {
public static function main(array $args) {
if (empty($args)) {
Console::writeLinef(
- 'XP %s { PHP %s & ZE %s } @ %s',
+ "\e[37;1mXP %s { PHP %s & ZE %s } @ %s\e[0m",
\xp::version(),
phpversion(),
zend_version(),
php_uname()
);
- Console::writeLine('Copyright (c) 2001-2016 the XP group');
- foreach (\lang\ClassLoader::getLoaders() as $delegate) {
- Console::writeLine($delegate->toString());
+ Console::writeLine('Copyright (c) 2001-2017 the XP group');
+ foreach (Module::$registered as $module) {
+ Console::writeLine($module->name(), "\e[32m: ", $module->classLoader()->toString(), "\e[0m");
}
return 1;
} else {
💡 How about also moving autoload.php
from src/main/php to the root directory?
<?php namespace com\example;
use lang\ClassLoader;
ClassLoader::registerPath('src/main/php', false,'xp-forge/patterns', [
'initialize' => function() {
echo '(autoload.php) Loaded module ', $this->name(), "\n";
}
]);
Libraries cannot drop module.xp until they require xp-framework/core 9.0.0
as minimum. Maybe it would be good if 8.x and 7.x would add forward-compatible support for this (7.9.0, 8.3.0) - then library authors could do this:
- "xp-framework/core": "^9.0 | ^8.0 | ^7.0"
+ "xp-framework/core": "^9.0 | ^8.3 | ^7.9"
...and still support XP7 - it's the last version with PHP 5.6 support, necessary for running on Debian Jessie, which bundles this version of PHP by default.
How about also moving autoload.php from src/main/php to the root directory?
It wouldn't be picked up by direct references via class.pth, then:
# Include this library
../inject/src/main/php/
So first we should either start putting module references there, see xp-runners/main#5 or reference autoload.php directly
# Local path and file references
src/autoload.php
# Dependencies, composer-style
?vendor/autoload.php
# Directly referencing dependencies, e.g. during development
../xp/inject/src/autoload.php
The autoload.php files would then:
<?php namespace inject;
use lang\ClassLoader;
ClassLoader::registerPath('src/main/php', false, 'xp-forge/inject', [
'initialize' => function() {
echo '(autoload.php) Loaded module ', $this->name(), "\n";
}
]);
ClassLoader::registerPath('src/test/php', false, 'xp-forge/inject@test');
...or maybe even a file src/module.php
, with the following:
<?php namespace inject;
use lang\ClassLoader;
ClassLoader::registerModule(__DIR__, 'xp-forge/inject', ['main/php', 'test/php'], [
'initialize' => function() {
echo '(autoload.php) Loaded module ', $this->name(), "\n";
}
]);