Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored entire Reflector to be more flexible #3

Merged
merged 27 commits into from
Jul 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
73a6965
Refactored into nicer directory structure
asgrim Jun 30, 2015
8c3b5d6
Refactored the source code loading to be much more flexible
asgrim Jun 30, 2015
a803023
Refactoring and tidying up
asgrim Jun 30, 2015
0ef3495
Renamed reflectClassFromString to reflectClassFromLocatedSource to be…
asgrim Jun 30, 2015
1491cc3
Fixed README.md for getClassesFromFile usage
asgrim Jun 30, 2015
52572f4
Get rid of unused variable in compile
asgrim Jun 30, 2015
89aacdc
Renamed FilenameSourceLocator to SingleFileSourceLocator
asgrim Jun 30, 2015
6f9c34d
Renamed locate to __invoke
asgrim Jun 30, 2015
4f43056
Introduced Symbol VO that will allow reflection of different symbol t…
asgrim Jul 2, 2015
d5be5bb
#4 Replace getClassesFromFile with getAllSymbols generic API
asgrim Jul 2, 2015
60b3198
Renamed interface to Reflection
asgrim Jul 2, 2015
013d360
Created a ClassReflector that replicates previous ease-of-use for ref…
asgrim Jul 2, 2015
d4e2480
Merge branch 'refactor-loading-symbol' into refactor-loading
asgrim Jul 2, 2015
c4913f8
Updated the README.md to use ClassReflector
asgrim Jul 2, 2015
2dc20ce
Renamed NodeCompiler to CompileNodeToValue for clarity
asgrim Jul 2, 2015
bc0d081
Assert that symbols are of type specified by ReflectionClass directly
asgrim Jul 2, 2015
9e651dc
Replaced is_null calls with null comparisons
asgrim Jul 2, 2015
4121d55
Custom exception type for InvalidDefaultValueType
asgrim Jul 2, 2015
06b4574
ltrim instead of silliness
asgrim Jul 2, 2015
1e0dcd6
Couple of small tweaks to Symbol validation and isMatchingReflector
asgrim Jul 2, 2015
89282e9
Corrected hinting of Generic->reflect method
asgrim Jul 2, 2015
e2e268c
Improve docblocks in ClassReflector
asgrim Jul 2, 2015
14d6322
Tidying up various calls
asgrim Jul 2, 2015
7c1d8a4
Docblock improvements
asgrim Jul 2, 2015
f2f775f
Fixed syntax error oopsie
asgrim Jul 2, 2015
61834e7
Added suggest for composer/composer
asgrim Jul 2, 2015
cccbb2e
Renamed Symbol to Identifier and created new IdentifierType VO
asgrim Jul 2, 2015
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
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,54 @@ Better Reflection
Mimics PHP's [reflection API](http://php.net/manual/en/book.reflection.php) but without actually loading the class at
any point. Like magic. Idea credit goes to @ocramius.

Example usage:
Example usage with the Composer autoloader:

```php
<?php

$classLoader = require "vendor/autoload.php";

$reflector = new Reflector($classLoader);
use BetterReflection\Reflector\ClassReflector;

$reflector = new ClassReflector(new ComposerSourceLocator($classLoader));
$reflectionClass = $reflector->reflect('Foo\Bar\MyClass');

echo $reflectionClass->getShortName(); // MyClass
echo $reflectionClass->getName(); // Foo\Bar\MyClass
echo $reflectionClass->getNamespaceName(); // Foo\Bar
```

Example usage for loading a class from a specific file:

```php
<?php

$reflector = new ClassReflector(new SingleFileSourceLocator('path/to/MyApp/MyClass.php'));
$reflectionClass = $reflector->reflect('MyApp\MyClass');

echo $reflectionClass->getShortName(); // MyClass
echo $reflectionClass->getName(); // MyApp\MyClass
echo $reflectionClass->getNamespaceName(); // MyApp
```

Example usage for loading a class from a string:

```php
<?php

$code = '<?php class Foo {};';

$reflector = new ClassReflector(new StringSourceLocator($code));
$reflectionClass = $reflector->reflect('Foo');

echo $reflectionClass->getShortName(); // Foo
```

Example usage to fetch a list of classes from a file

```php
<?php

$reflector = new ClassReflector(new SingleFileSourceLocator('path/to/file.php'));
$classes = $reflector->getClassesFromFile();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getClassesFromFile without parameter? Seems a bit weird. The API is probably also redundant, now that you have the locator:

$allInString = (new Reflector(new FilenameSourceLocator('path/to/file.php'))->getAllClasses();
$allInFile = (new Reflector(new StringSourceLocator($code))->getAllClasses();
$allAutoloadable = (new Reflector(new ComposerSourceLocator($classLoader))->getAllClasses();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created issue #4 to implement this later

```
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"BetterReflectionTest\\": "test"
}
},
"suggest": {
"composer/composer": "Required to use the ComposerSourceLocator thing"
},
"minimum-stability": "dev",
"prefer-stable": true
}
38 changes: 19 additions & 19 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 52 additions & 0 deletions src/Identifier/Identifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace BetterReflection\Identifier;

use PhpParser\Node;

class Identifier
{
/**
* @var string
*/
private $name;

/**
* @var IdentifierType
*/
private $type;

public function __construct($name, IdentifierType $type)
{
$this->type = $type;

$name = ltrim($name, '\\');
// @todo validate the name somehow (see issue #20)
$this->name = (string)$name;
}

/**
* @return string
*/
public function getName()
{
return $this->name;
}

/**
* @return IdentifierType
*/
public function getType()
{
return $this->type;
}

/**
* @todo implement this
* @return bool
*/
public function isLoaded()
{
return false;
}
}
56 changes: 56 additions & 0 deletions src/Identifier/IdentifierType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace BetterReflection\Identifier;

use PhpParser\Node;
use BetterReflection\Reflection\ReflectionClass;
use BetterReflection\Reflection\Reflection;

class IdentifierType
{
const IDENTIFIER_CLASS = ReflectionClass::class;

/**
* @var string[]
*/
private $validTypes = [
self::IDENTIFIER_CLASS,
];

/**
* @var string
*/
private $name;

public function __construct($type = self::IDENTIFIER_CLASS)
{
if (!in_array($type, $this->validTypes, true)) {
throw new \InvalidArgumentException(sprintf(
'%s is not a valid identifier type',
$type
));
}
$this->name = $type;
}

/**
* @return string
*/
public function getName()
{
return $this->name;
}

/**
* @return string
*/
public function getDisplayName()
{
return ucfirst(basename($this->name));
}

public function isMatchingReflector(Reflection $reflector)
{
return $this->name === get_class($reflector);
}
}
45 changes: 45 additions & 0 deletions src/NodeCompiler/CompileNodeToValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace BetterReflection\NodeCompiler;

use PhpParser\Node;

class CompileNodeToValue
{
/**
* Compile an expression from a node into a value
*
* @param Node $node
* @return mixed
*/
public function __invoke(Node $node)
{
switch (get_class($node)) {
case Node\Scalar\String_::class:
case Node\Scalar\DNumber::class:
case Node\Scalar\LNumber::class:
return $node->value;
case Node\Expr\Array_::class:
return []; // @todo compile expression
case Node\Expr\ConstFetch::class:
if ($node->name->parts[0] == 'null') {
return null;
} else if ($node->name->parts[0] == 'false') {
return false;
} else if ($node->name->parts[0] == 'true') {
return true;
} else {
// @todo this should evaluate the VALUE, not the name
return $node->name->parts[0];
}
break;
case Node\Expr\ClassConstFetch::class:
// @todo this should evaluate the VALUE, not the name
$className = implode('\\', $node->class->parts);
$constName = $node->name;
return $className . '::' . $constName;
default:
throw new \LogicException('Unable to compile expression: ' . $type);
}
}
}
7 changes: 7 additions & 0 deletions src/Reflection/Exception/InvalidDefaultValueType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace BetterReflection\Reflection\Exception;

class InvalidDefaultValueType extends \RuntimeException
{
}
20 changes: 20 additions & 0 deletions src/Reflection/Reflection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace BetterReflection\Reflection;

/**
* This interface is used internally by the Generic reflector in order to
* ensure we are working with BetterReflection reflections
*
* @internal
*/
interface Reflection
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing docblocks (overall)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is for internal use, use @internal

{
/**
* Get the name of the reflection (e.g. if this is a ReflectionClass this
* will be the class name).
*
* @return string
*/
public function getName();
}
Loading