Skip to content

Commit cdda55c

Browse files
committed
Implement metadata support in all level elements
1 parent 07ce695 commit cdda55c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+586
-16
lines changed

Diff for: Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ test:
3232
docker run -it --rm -v${CURDIR}:/github/workspace phpdoc/phpunit-ga
3333
docker run -it --rm -v${CURDIR}:/data -w /data php:7.2 -f ./tests/coverage-checker.php 94
3434

35+
.PHONY: benchmark
36+
benchmark:
37+
docker run -it --rm -v${CURDIR}:/opt/project -w /opt/project php:7.4-cli tools/phpbench run
38+
3539
.PHONY: pre-commit-test
3640
pre-commit-test: test phpcs phpstan
3741

Diff for: docs/index.rst

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Reflection
2+
==========
3+
4+
.. toctree::
5+
:hidden:
6+
7+
meta-data

Diff for: docs/meta-data.rst

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
Metadata
2+
=====
3+
4+
The model of this library is as closed as possible.
5+
Main reason is because consumers of the library should rely on cache.
6+
A mutable and flexible interface of the model would most likely break the caching.
7+
However after some time the users to this library started requesting for a more flexible format.
8+
This is why metadata was introduced.
9+
10+
Create your first metadata
11+
--------------------------
12+
13+
First step is to create your own metadata implementation.
14+
15+
.. code:: php
16+
final class Hook implements \phpDocumentor\Reflection\Metadata\Metadata
17+
{
18+
private string $hook;
19+
20+
public function __construct(string $hook)
21+
{
22+
$this->hook = $hook;
23+
}
24+
25+
public function key(): string
26+
{
27+
return "project-metadata";
28+
}
29+
30+
public function hook(): string
31+
{
32+
return $this->hook;
33+
}
34+
}
35+
36+
.. note::
37+
We do highly recommend to keep your metadata objects small.
38+
When reflecting a large project the number of objects will grow fast.
39+
40+
Now we have an class that can be used it is time to create a :php:class:`\phpDocumentor\Reflection\Php\ProjectFactoryStrategy`.
41+
Strategies are used to reflect nodes in the AST of `phpparser`_.
42+
43+
In the example below we are adding the Hook metadata to any functions containing a function call.
44+
45+
.. code:: php
46+
47+
use \phpDocumentor\Reflection\Php\Function;
48+
49+
final class HookStrategy implements \phpDocumentor\Reflection\Php\ProjectFactoryStrategy
50+
{
51+
public function matches(ContextStack $context, object $object): bool
52+
{
53+
return $this->context->peek() instanceof Function_ &&
54+
$object instanceof \PhpParser\Node\Expr\FuncCall &&
55+
((string)$object->name) === 'hook'
56+
}
57+
58+
public function create(ContextStack $context, object $object, StrategyContainer $strategies): void
59+
{
60+
$method = $context->peek();
61+
$method->addMetadata(new Hook($object->args[0]->value));
62+
}
63+
}
64+
65+
.. note::
66+
To speed up the reflection of your project the default factory instance has a Noop strategy. This strategy will
67+
ignore all statements that are not handled by any strategy. Keep this in mind when implementing your own strategies
68+
especially the statements you are looking for are nested in other statements like a ``while`` loop.
69+
70+
Finally add your new strategy to the project factory.
71+
72+
.. code:: php
73+
74+
$factory = \phpDocumentor\Reflection\Php\ProjectFactory::createInstance();
75+
$factory->addStrategy(new HookStrategy());
76+
77+
.. _phpparser: https://github.com/nikic/PHP-Parser/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link http://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Reflection\Metadata;
15+
16+
interface MetaDataContainer
17+
{
18+
public function addMetadata(Metadata $metadata): void;
19+
20+
/** @return Metadata[] */
21+
public function getMetadata(): array;
22+
}

Diff for: src/phpDocumentor/Reflection/Metadata/Metadata.php

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link http://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Reflection\Metadata;
15+
16+
interface Metadata
17+
{
18+
public function key(): string;
19+
}

Diff for: src/phpDocumentor/Reflection/Php/Class_.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@
1717
use phpDocumentor\Reflection\Element;
1818
use phpDocumentor\Reflection\Fqsen;
1919
use phpDocumentor\Reflection\Location;
20+
use phpDocumentor\Reflection\Metadata\MetaDataContainer as MetaDataContainerInterface;
2021

2122
/**
2223
* Descriptor representing a Class.
2324
*/
2425
// @codingStandardsIgnoreStart
25-
final class Class_ implements Element
26+
final class Class_ implements Element, MetaDataContainerInterface
2627
// @codingStandardsIgnoreEnd
2728
{
29+
use MetadataContainer;
30+
2831
/** @var Fqsen Full Qualified Structural Element Name */
2932
private $fqsen;
3033

Diff for: src/phpDocumentor/Reflection/Php/Constant.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@
1717
use phpDocumentor\Reflection\Element;
1818
use phpDocumentor\Reflection\Fqsen;
1919
use phpDocumentor\Reflection\Location;
20+
use phpDocumentor\Reflection\Metadata\MetaDataContainer as MetaDataContainerInterface;
2021

2122
/**
2223
* Descriptor representing a constant
2324
*/
24-
final class Constant implements Element
25+
final class Constant implements Element, MetaDataContainerInterface
2526
{
27+
use MetadataContainer;
28+
2629
/** @var Fqsen */
2730
private $fqsen;
2831

Diff for: src/phpDocumentor/Reflection/Php/EnumCase.php

+9-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
use phpDocumentor\Reflection\Element;
99
use phpDocumentor\Reflection\Fqsen;
1010
use phpDocumentor\Reflection\Location;
11+
use phpDocumentor\Reflection\Metadata\MetaDataContainer as MetaDataContainerInterface;
1112

12-
final class EnumCase implements Element
13+
final class EnumCase implements Element, MetaDataContainerInterface
1314
{
15+
use MetadataContainer;
16+
1417
/** @var Fqsen */
1518
private $fqsen;
1619

@@ -24,6 +27,10 @@ final class EnumCase implements Element
2427

2528
public function __construct(Fqsen $fqsen, ?DocBlock $docBlock, ?Location $location = null, ?string $value = null)
2629
{
30+
if ($location === null) {
31+
$location = new Location(-1);
32+
}
33+
2734
$this->fqsen = $fqsen;
2835
$this->docBlock = $docBlock;
2936
$this->location = $location;
@@ -45,7 +52,7 @@ public function getDocBlock(): ?DocBlock
4552
return $this->docBlock;
4653
}
4754

48-
public function getLocation(): ?Location
55+
public function getLocation(): Location
4956
{
5057
return $this->location;
5158
}

Diff for: src/phpDocumentor/Reflection/Php/Enum_.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,20 @@
1717
use phpDocumentor\Reflection\Element;
1818
use phpDocumentor\Reflection\Fqsen;
1919
use phpDocumentor\Reflection\Location;
20+
use phpDocumentor\Reflection\Metadata\MetaDataContainer as MetaDataContainerInterface;
2021
use phpDocumentor\Reflection\Type;
2122

22-
final class Enum_ implements Element
23+
final class Enum_ implements Element, MetaDataContainerInterface
2324
{
25+
use MetadataContainer;
26+
2427
/** @var Fqsen Full Qualified Structural Element Name */
2528
private $fqsen;
2629

2730
/** @var DocBlock|null */
2831
private $docBlock;
2932

30-
/** @var Location|null */
33+
/** @var Location */
3134
private $location;
3235

3336
/** @var EnumCase[] */
@@ -76,7 +79,7 @@ public function getDocBlock(): ?DocBlock
7679
return $this->docBlock;
7780
}
7881

79-
public function getLocation(): ?Location
82+
public function getLocation(): Location
8083
{
8184
return $this->location;
8285
}

Diff for: src/phpDocumentor/Reflection/Php/Factory/AbstractFactory.php

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
declare(strict_types=1);
44

5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link http://phpdoc.org
12+
*/
13+
514
namespace phpDocumentor\Reflection\Php\Factory;
615

716
use InvalidArgumentException;

Diff for: src/phpDocumentor/Reflection/Php/Factory/Function_.php

+12-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
use PhpParser\Node\Stmt\Function_ as FunctionNode;
2222
use Webmozart\Assert\Assert;
2323

24+
use function is_array;
25+
2426
/**
2527
* Strategy to convert Function_ to FunctionDescriptor
2628
*
@@ -57,10 +59,19 @@ protected function doCreate(
5759

5860
$file->addFunction($function);
5961

62+
$thisContext = $context->push($function);
6063
foreach ($object->params as $param) {
61-
$thisContext = $context->push($function);
6264
$strategy = $strategies->findMatching($thisContext, $param);
6365
$strategy->create($thisContext, $param, $strategies);
6466
}
67+
68+
if (!is_array($object->stmts)) {
69+
return;
70+
}
71+
72+
foreach ($object->stmts as $stmt) {
73+
$strategy = $strategies->findMatching($thisContext, $stmt);
74+
$strategy->create($thisContext, $stmt, $strategies);
75+
}
6576
}
6677
}

Diff for: src/phpDocumentor/Reflection/Php/Factory/Method.php

+12-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
use PhpParser\Node\Stmt\ClassMethod;
2525
use Webmozart\Assert\Assert;
2626

27+
use function is_array;
28+
2729
/**
2830
* Strategy to create MethodDescriptor and arguments when applicable.
2931
*/
@@ -67,11 +69,20 @@ protected function doCreate(
6769
);
6870
$methodContainer->addMethod($method);
6971

72+
$thisContext = $context->push($method);
7073
foreach ($object->params as $param) {
71-
$thisContext = $context->push($method);
7274
$strategy = $strategies->findMatching($thisContext, $param);
7375
$strategy->create($thisContext, $param, $strategies);
7476
}
77+
78+
if (!is_array($object->stmts)) {
79+
return;
80+
}
81+
82+
foreach ($object->stmts as $stmt) {
83+
$strategy = $strategies->findMatching($thisContext, $stmt);
84+
$strategy->create($thisContext, $stmt, $strategies);
85+
}
7586
}
7687

7788
/**

Diff for: src/phpDocumentor/Reflection/Php/File.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@
1515

1616
use phpDocumentor\Reflection\DocBlock;
1717
use phpDocumentor\Reflection\Fqsen;
18+
use phpDocumentor\Reflection\Metadata\MetaDataContainer as MetaDataContainerInterface;
1819

1920
use function basename;
2021

2122
/**
2223
* Represents a file in the project.
2324
*/
24-
final class File
25+
final class File implements MetaDataContainerInterface
2526
{
27+
use MetadataContainer;
28+
2629
/** @var DocBlock|null */
2730
private $docBlock = null;
2831

Diff for: src/phpDocumentor/Reflection/Php/Function_.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@
1717
use phpDocumentor\Reflection\Element;
1818
use phpDocumentor\Reflection\Fqsen;
1919
use phpDocumentor\Reflection\Location;
20+
use phpDocumentor\Reflection\Metadata\MetaDataContainer as MetaDataContainerInterface;
2021
use phpDocumentor\Reflection\Type;
2122
use phpDocumentor\Reflection\Types\Mixed_;
2223

2324
/**
2425
* Descriptor representing a function
2526
*/
2627
// @codingStandardsIgnoreStart
27-
final class Function_ implements Element
28+
final class Function_ implements Element, MetaDataContainerInterface
2829
// // @codingStandardsIgnoreEnd
2930
{
31+
use MetadataContainer;
32+
3033
/** @var Fqsen Full Qualified Structural Element Name */
3134
private $fqsen;
3235

Diff for: src/phpDocumentor/Reflection/Php/Interface_.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
use phpDocumentor\Reflection\Element;
1818
use phpDocumentor\Reflection\Fqsen;
1919
use phpDocumentor\Reflection\Location;
20+
use phpDocumentor\Reflection\Metadata\MetaDataContainer as MetaDataContainerInterface;
2021
use Webmozart\Assert\Assert;
2122

2223
/**
2324
* Descriptor representing an Interface.
2425
*/
25-
final class Interface_ implements Element
26+
final class Interface_ implements Element, MetaDataContainerInterface
2627
{
28+
use MetadataContainer;
29+
2730
/** @var Fqsen Full Qualified Structural Element Name */
2831
private $fqsen;
2932

0 commit comments

Comments
 (0)