Open thekid opened 3 years ago
The xp-framework/reflection library comes in at around 1700 LOC:
$ cloc-1.82.pl src/main/
43 text files.
43 unique files.
8 files ignored.
github.com/AlDanial/cloc v 1.82 T=0.15 s (280.1 files/s, 19744.7 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
PHP 42 380 861 1720
-------------------------------------------------------------------------------
SUM: 42 380 861 1720
-------------------------------------------------------------------------------
The code in the core library's lang.reflect
package is around 1500 lines of code, additionally, more than 400 lines would be removed from lang.XPClass
, making both libraries about equally heavy.
The lang.reflect.Proxy
class would be dropped, there has so far only been one library using it, which could be rewritten to include this class (or a specialized version of it).
XP Framework's generic types, which heavily rely on reflection (especially on annotations), have only really been used inside xp-framework/collections
, really, so the first idea would be to remove them from core. However, it's unclear how the type system can be extended from the outside.
$ cloc-1.82.pl src/main/php/lang/GenericTypes.class.php
1 text file.
1 unique file.
0 files ignored.
github.com/AlDanial/cloc v 1.82 T=0.06 s (16.8 files/s, 5807.0 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
PHP 1 16 30 299
-------------------------------------------------------------------------------
Basically, this infrastructure makes declaring reusable collection classes easier.
#[Generic('T')]
class Vector {
private $elements;
#[Generic(params: ['T'])]
public function __construct(... $elements) {
$this->elements= $elements;
}
}
$v= create('new Vector<string>', ['hello', 'world']);
class Vector {
private $elements= [];
public function __construct(Type $type, ... $elements) {
$this->type= $type;
foreach ($elements as $element) {
if (!$type->isInstance($element)) throw ...
$this->elements[]= $element;
}
}
}
$v= new Vector(Primitive::$STRING, 'hello', 'world');
The most useful class in the xp-framework/collections library is util.collections.HashTable
, which can map arbitrary values to arbitray values. However, this can also be done using PHP's SplObjectStorage class.
The most useful feature is the type safety, which could be implemented by something along the lines of:
$v= Vectors::of('string')->new('hello', 'world'); // returns a Vector class
This library could come with something like a Generics
class which would extend lang.Type
and provide utility methods for verifying arguments. The only thing that wouldn't work this way would be using is()
or Type::forName()
from XP core.
It boils down to whether a language (or here: something that extends the PHP language) should have generics. GoLang has done without them for over a decade, and has put lots of thought into making it viable, see https://blog.golang.org/generics-next-step.
Removing generics would mean:
hashCode()
as this is the only place they're really used - thus making the Value
interface way easier to implementcreate()
- its sole purpose is to create generic instancesThe following changes make the transition to xp-framework/reflection
easier:
Before this can be implemented, XP core needs to be migrated to the new testing library, see #344. Otherwise, we'll simply see Call to undefined method lang\XPClass::getMethods())
when trying to run the framework's unittests.
The Package
class contains the getClasses()
method which is quite convenient; and needs to be replaced by the following if you don't want a dependency on xp-framework/reflection
:
/**
* Returns XPClass instances for all classes inside a given package
*
* @param string $package
* @return iterable
*/
private static function classesIn($package) {
$offset= -strlen(\xp::CLASS_FILE_EXT);
$cl= ClassLoader::getDefault();
foreach ($cl->packageContents($package) as $item) {
if (0 === substr_compare($item, \xp::CLASS_FILE_EXT, $offset)) {
yield $cl->loadClass($package.'.'.substr($item, 0, $offset));
}
}
}
...which exposes quite a bit of internals. Maybe the ClassLoader
API itself could provide a packageTypes()
method?
Re the Proxy class - https://github.com/xp-framework/rfc/issues/338#issuecomment-774665217
The Proxy class will be removed in XP 12, see https://github.com/xp-framework/core/pull/341
The test
library was still using XP reflection inside its FromDirectory
source. This was changed in xp-framework/test@46fc70e06876c500d6b04d7561836010212cb377 and released in https://github.com/xp-framework/test/releases/tag/v2.1.0
The logging
library was changed to use the reflection library in https://github.com/xp-framework/logging/releases/tag/v11.2.0
Scope of Change
This RFC suggests extracting reflection to its own library, while the type system will continue to exist.
Rationale
Reflection is a big block of code with quite a bit of legacy, including an outdated concept of annotations which doesn't fit PHP 8 attributes well.
Functionality
This is the
lang.reflect
package, which will be replaced by https://github.com/xp-framework/reflection except for theProxy
class, which we might extract to its own library or simply move to the mocking library:The
lang.XPClass
class will be stripped down to its essentials, where it will serve the purpose of reflecting value types.Security considerations
None.
Speed impact
Reduces the size of XP core:
Dependencies
Generics.
Related documents
https://github.com/xp-framework/unittest/pull/43