nastuzzi-samy/reflection-namespace

Reflect a namespace, give its classes, its sub-namespaces and more

v1.0.1 2019-05-23 22:13 UTC

This package is auto-updated.

Last update: 2024-04-26 06:27:24 UTC


README

Travis Build Issues Stars License

Introduction

Instead of searching all classes, sub directories in a specific directory, why can't you use their root namespace ?

Moreover, sometimes files within the same namespace are defined in different directories, multiple researches are needed here to get all of them.

PHP has by default multiple Reflector classes: class, parameters, constant, methods, etc. But no solutions exist to reflect a namespace. It could be usefull, now, as all projects use different packages via Composer.

The ReflectionNamespace class loads its data (sub namespaces, classes) from Composer. It uses PSR-0 (disabled by default), PSR-4, classmap and files autoloaders. It loads also from already declared classes, traits and interfaces (also disabled by default).

Installation

Simple installation via Composer:

composer install nastuzzi-samy/reflection-namespace

As it is working with the Composer engine (autoloaders), it needs to be implemented in a Composer project.

Usage

First of all, the ReflectionNamespace class is on the root namespace as the other Reflector classes.

Project example structure:

app/
	Http/
		Controller.php
	Models/
		User.php
vendor/
	...
	random-package/  # RandomPackage defines app/ as \App namespace also
		app/
			Console/
			Models/
				Group.php

Creation

To create a new ReflectionNamespace, you need to pass it the namespace you want to work on as a string:

<?php

// Regroup the namespace generated by our projet and the RandomPackage package:
new \ReflectionNamespace('App');
new \ReflectionNamespace('App\\');  // It is the same that the previous one.
new \ReflectionNamespace('\\App\\');  // Same.
new \ReflectionNamespace('\\App');  // Same.

// Regroup the namespace generated by our RandomPackage package:
new \ReflectionNamespace('App\Console');
new \ReflectionNamespace('App\Console\\');  // It is the same that the previous one.
new \ReflectionNamespace('\\App\Console');  // Same.
new \ReflectionNamespace('\\App\Console\\');  // Same.

?>

Get information

As it is expensive, the ReflectionNamespace only loads classes and namespaces only when it is asked to. Mainly, you can use the class only to parse the short and long name of a namespace without carring about resource consumption.

<?php

$modelsReflection = new \ReflectionNamespace('App\\Models');

echo $modelsReflection->getName();  // App\Models
echo $modelsReflection->getShortName();  // Models
echo $modelsReflection->getParentName();  // App

?>

Get classes and namespaces

By getting classes or namespaces, the ReflectionNamespace class will load every data, browsing all Composer autoloaders and in some case, if Composer did not cache all files/classes, search in directories (case for PSR-0 and PSR-4 only).

<?php

$modelsReflection = new \ReflectionNamespace('App\\Models');

// Equivalent to: new \ReflectionNamespace('App');
$appReflection = $modelsReflection->getParent();

/*
Get all class names under App\Models.
Equivalent to:
[
	'User' => 'App\\Models\\User',
	'Group' => 'App\\Models\\Group',
];
 */
$modelsReflection->getClassNames();

/*
Get all classes under App\Models.
Equivalent to:
[
	'User' => new \ReflectionClass('App\\Models\\User'),
	'Group' => new \ReflectionClass('App\\Models\\Group'),
];
 */
$modelsReflection->getClasses();

/*
Get all namespace full names under App.
Equivalent to:
[
	'Console' => 'App\\Console',
	'Http' => 'App\\Http',
	'Models' => 'App\\Models',
];
 */
$appReflection->getNamespaceNames();

/*
Get all namespaces under App.
Equivalent to:
[
	'Console' => new \ReflectionNamespace('App\\Console'),
	'Http' => new \ReflectionNamespace('App\\Http'),
	'Models' => new \ReflectionNamespace('App\\Models'),
];
 */
$appReflection->getNamespaces();

?>

Of course, you can get a precise class or namespace with getClass and getNamespace. Or you can check if the namespace owns a class or a sub namespace with hasClass and hasNamespace.

<?php

// Equivalent to: new \ReflectionClass('App\\Models\\User');
$modelsReflection->getClass('User');
// Throw an exception.
$modelsReflection->getClass('NoModel');

echo $appReflection->hasNamespace('Models'); // TRUE
echo $modelsReflection->hasNamespace('User'); // FALSE

?>

Advanced usage

Enable loading from PSR-0

By default, PSR-0 loaders are not handled (as it is deprecated) and the reflection could lead to a uncompleted search. For that, to use PSR-0 loaders, you can enable the usage of it by calling the static method:

<?php

// Ask the class to load also from PSR-0.
\ReflectionNamespace::loadPRS0(TRUE);

// Refresh all loaded data:
$modelsReflection->reload();
$appReflection->reload();

// Ask the class not to load from PSR-0.
\ReflectionNamespace::loadPRS0(FALSE);

?>

Enable loading from loaded classes, interfaces and traits

By default, loading all already declared classes, interfaces and traits is not handled and the reflection could lead to a uncompleted search. This is because it could be really expensive in a large project, using a lot of heavy packages. It is rarely usefull because usually, all declared classes are listed by Composer. For any reason, if you want to load all of them, you can enable the usage of it by calling the static method:

<?php

// Ask the class to load also from loaded classes, interfaces and traits.
\ReflectionNamespace::loadDeclaredClasses(TRUE);

// Refresh all loaded data:
$modelsReflection->reload();
$appReflection->reload();

// Ask the class not to load from loaded classes, interfaces and traits.
\ReflectionNamespace::loadDeclaredClasses(FALSE);

?>

Manipulate loaders

You can get the based loaders with the static method: getLoaders. Loaders are common to all ReflectionNamespace objects.

As written in the test code tests/0-DefinitionTest.php, you can create your own autoloader in anytime. It is important to ask the class to reload all loaders and reload each object to use the full loader list:

<?php

// Ask to reload all loaders:
\ReflectionNamespace::getLoaders(TRUE);

// Refresh all loaded data to use the full loader list:
$modelsReflection->reload();
$appReflection->reload();

?>

If a loader will only impact an object, you can also ask the ReflectionNamespace object to load from a new loader:

<?php

$myNewLoader = new \Composer\Autoload\ClassLoader();

/* work on $myNewLoader... */

$appReflection->fillWithLoader($myNewLoader);

?>

You can also fill with a simple class map:

<?php

$modelsReflection->fillWithClassMap([
	'App\\Models\\Article',
	'App\\Models\\Comment',
]);

?>

Extend the class

Of course, the class is extendable. All methods and properties are protected in order to allow you editing them in a sub class.

Be carefull and be sure to fully understand how it works before investaging in.

Contribution

Report bugs

You have a weird behavior, some classes are not detected, namespaces are missing, exceptions are detected ? Open a ticket with the maximum of information and let us help you :)

Develop

First, fork the project in your organization. When it is done, you need to clone your repository obviously.

After cloning, you need to prepare all the future tests by running the following command: composer prepare-test

Make your modifications and before pushing and opening a PR, run this and be sure that it works great: composer test

Of course, if you add features and code, or simply fix a noticable bug, you need to write tests :)

Thanks by advance for the contributions ;)

Donate

As it took me time and as I still a simple student who needs coffee, do not hesitate to donate here, it would be a pleasure and a recognition of my work :)

PayPal