├── LICENSE
├── README.md
├── bin
└── phpdoc-md
├── composer.json
├── docs.md
├── src
└── PHPDocsMD
│ ├── ClassEntity.php
│ ├── ClassEntityFactory.php
│ ├── CodeEntity.php
│ ├── Console
│ ├── CLI.php
│ └── PHPDocsMDCommand.php
│ ├── DocInfo.php
│ ├── DocInfoExtractor.php
│ ├── FunctionEntity.php
│ ├── FunctionFinder.php
│ ├── MDTableGenerator.php
│ ├── ParamEntity.php
│ ├── Reflector.php
│ ├── ReflectorInterface.php
│ ├── TableGenerator.php
│ ├── UseInspector.php
│ └── Utils.php
└── test
├── ExampleClass.php
├── MDTableGeneratorTest.php
├── ReflectorTest.php
└── UseInspectorTest.php
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015-2016 Victor Jonsson
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so,
8 | subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP-Markdown-Documentation-Generator
2 |
3 | Documentation is just as important as the code it's refering to. With this command line tool
4 | you will be able to write your documentation once, and only once!
5 |
6 | This project will write a single-page markdown-formatted API document based on the DocBlock comments in your source code.
7 |
8 | 
9 |
10 | ### Example
11 |
12 | Let's say you have your PHP classes in a directory named "src". Each class has its own file that is named after the class.
13 |
14 | ```
15 | - src/
16 | - MyObject.php
17 | - OtherObject.php
18 | ```
19 |
20 | Write your code documentation following the standard set by [phpdoc](http://www.phpdoc.org/).
21 |
22 | ```php
23 | namespace Acme;
24 |
25 | /**
26 | * This is a description of this class
27 | */
28 | class MyObject {
29 |
30 | /**
31 | * This is a function description
32 | * @param string $str
33 | * @param array $arr
34 | * @return Acme\OtherObject
35 | */
36 | function someFunc($str, $arr=array()) {
37 |
38 | }
39 | }
40 | ```
41 |
42 | Then, running `$ phpdoc-md generate src > api.md` will write your API documentation to the file api.md.
43 |
44 | [Here you can see a rendered example](https://github.com/victorjonsson/PHP-Markdown-Documentation-Generator/blob/master/docs.md)
45 |
46 | Only public and protected functions will be a part of the documentation, but you can also add `@ignore` to any function or class to exclude it from the docs. Phpdoc-md will try to guess the return type of functions that don't explicitly declare one. The program uses reflection to get as much information as possible out of the code so that functions that are missing DocBlock comments will still be included in the generated documentation.
47 |
48 | ### Requirements
49 |
50 | - PHP version >= 5.3.2
51 | - Reflection must be enabled in php.ini
52 | - Each class must be defined in its own file with the file name being the same as the class name
53 | - The project should use [Composer](https://getcomposer.org/)
54 |
55 | ### Installation / Usage
56 |
57 | This command line tool can be installed using [composer](https://getcomposer.org/).
58 |
59 | From the local working directory of the project that you would like to document, run:
60 | ```
61 | $ composer require --dev victorjonsson/markdowndocs
62 | ```
63 | This will add victorjonsson/markdowndocs to the `require-dev` section of your project's composer.json file. The phpdoc-md executable will automatically be copied to your project's `vendor/bin` directory.
64 |
65 | ##### Generating docs
66 |
67 | The `generate` command generates your project's API documentation file. The command line tool needs to know whether you want to generate docs for a certain class, or if it should process every class in a specified directory search path.
68 |
69 | ```
70 | # Generate docs for a certain class
71 | $ ./vendor/bin/phpdoc-md generate Acme\\NS\\MyClass
72 |
73 | # Generate docs for several classes (comma separated)
74 | $ ./vendor/bin/phpdoc-md generate Acme\\NS\\MyClass,Acme\\OtherNS\\OtherClass
75 |
76 | # Generate docs for all classes in a source directory
77 | $ ./vendor/bin/phpdoc-md generate includes/src
78 |
79 | # Generate docs for all classes in a source directory and send output to the file api.md
80 | $ ./vendor/bin/phpdoc-md generate includes/src > api.md
81 | ```
82 |
83 | * Note that any class to be documented must be loadable using the autoloader provided by composer. *
84 |
85 | ##### Bootstrapping
86 |
87 | If you are not using the composer autoloader, or if there is something else that needs to be done before your classes can be instantiated, then you may request phpdoc-md to load a php bootstrap file prior to generating the docs
88 |
89 | `$ ./vendor/bin/phpdoc-md generate --bootstrap=includes/init.php includes/src > api.md`
90 |
91 | ##### Excluding directories
92 |
93 | You can tell the command line tool to ignore certain directories in your class path by using the `--ignore` option.
94 |
95 | `$ ./phpdoc-md generate --ignore=test,examples includes/src > api.md`
96 |
97 |
--------------------------------------------------------------------------------
/bin/phpdoc-md:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | run();
16 | exit($code);
17 |
18 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "victorjonsson/markdowndocs",
3 | "description": "Command line tool for generating markdown-formatted class documentation",
4 | "minimum-stability": "dev",
5 | "homepage" : "https://github.com/victorjonsson/PHP-Markdown-Documentation-Generator",
6 | "license" : "MIT",
7 | "version" : "1.3.8",
8 | "authors": [{
9 | "name": "Victor Jonsson",
10 | "email": "kontakt@victorjonsson.se"
11 | }],
12 | "require" : {
13 | "php" : ">=5.5.0",
14 | "symfony/console": ">=2.6"
15 | },
16 | "require-dev" : {
17 | "phpunit/phpunit": "9.5"
18 | },
19 | "bin":["bin/phpdoc-md"],
20 | "autoload": {
21 | "psr-0": {"PHPDocsMD": "src/"}
22 | },
23 | "autoload-dev": {
24 | "psr-4": {
25 | "Acme\\": "test"
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/docs.md:
--------------------------------------------------------------------------------
1 | ## Table of contents
2 |
3 | - [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity)
4 | - [\PHPDocsMD\ClassEntityFactory](#class-phpdocsmdclassentityfactory)
5 | - [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)
6 | - [\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo)
7 | - [\PHPDocsMD\DocInfoExtractor](#class-phpdocsmddocinfoextractor)
8 | - [\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity)
9 | - [\PHPDocsMD\FunctionFinder](#class-phpdocsmdfunctionfinder)
10 | - [\PHPDocsMD\MDTableGenerator](#class-phpdocsmdmdtablegenerator)
11 | - [\PHPDocsMD\ParamEntity](#class-phpdocsmdparamentity)
12 | - [\PHPDocsMD\Reflector](#class-phpdocsmdreflector)
13 | - [\PHPDocsMD\ReflectorInterface (interface)](#interface-phpdocsmdreflectorinterface)
14 | - [\PHPDocsMD\UseInspector](#class-phpdocsmduseinspector)
15 | - [\PHPDocsMD\Utils](#class-phpdocsmdutils)
16 | - [\PHPDocsMD\Console\CLI](#class-phpdocsmdconsolecli)
17 | - [\PHPDocsMD\Console\PHPDocsMDCommand](#class-phpdocsmdconsolephpdocsmdcommand)
18 |
19 |
20 |
21 | ### Class: \PHPDocsMD\ClassEntity
22 |
23 | > Object describing a class or an interface
24 |
25 | | Visibility | Function |
26 | |:-----------|:---------|
27 | | public | generateAnchor() : string
Generates an anchor link out of the generated title (see generateTitle) |
28 | | public | generateTitle(string $format=`'%label%: %name% %extra%'`) : string
Generate a title describing the class this object is referring to |
29 | | public | getExtends() : string |
30 | | public | getFunctions() : [\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity)[] |
31 | | public | getInterfaces() : array |
32 | | public | hasIgnoreTag(bool $toggle=null) : bool |
33 | | public | isAbstract(bool $toggle=null) : bool |
34 | | public | isInterface(bool $toggle=null) : bool |
35 | | public | isNative(bool $toggle=null) : bool |
36 | | public | isSame(string/object $class) : bool
Check whether this object is referring to given class name or object instance |
37 | | public | setExtends(string $extends) : void |
38 | | public | setFunctions([\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity)[] $functions) : void |
39 | | public | setInterfaces(array $implements) : void |
40 | | public | setName(string $name) : void |
41 |
42 | *This class extends [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)*
43 |
44 |
45 |
46 | ### Class: \PHPDocsMD\ClassEntityFactory
47 |
48 | > Class capable of creating ClassEntity objects
49 |
50 | | Visibility | Function |
51 | |:-----------|:---------|
52 | | public | __construct([\PHPDocsMD\DocInfoExtractor](#class-phpdocsmddocinfoextractor) $docInfoExtractor) : void |
53 | | public | create([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php) $reflection) : mixed |
54 |
55 |
56 |
57 | ### Class: \PHPDocsMD\CodeEntity
58 |
59 | > Object describing a piece of code
60 |
61 | | Visibility | Function |
62 | |:-----------|:---------|
63 | | public | getDeprecationMessage() : string |
64 | | public | getDescription() : string |
65 | | public | getExample() : string |
66 | | public | getName() : string |
67 | | public | isDeprecated(bool $toggle=null) : void/bool |
68 | | public | setDeprecationMessage(string $deprecationMessage) : void |
69 | | public | setDescription(string $description) : void |
70 | | public | setExample(string $example) : void |
71 | | public | setName(string $name) : void |
72 |
73 |
74 | ### Class: \PHPDocsMD\DocInfo
75 |
76 | > Class containing information about a function/class that's being made available via a comment block
77 |
78 | | Visibility | Function |
79 | |:-----------|:---------|
80 | | public | __construct(array $data) : void |
81 | | public | getDeprecationMessage() : string |
82 | | public | getDescription() : string |
83 | | public | getExample() : string |
84 | | public | getParameterInfo(string $name) : array |
85 | | public | getParameters() : array |
86 | | public | getReturnType() : string |
87 | | public | shouldBeIgnored() : bool |
88 | | public | shouldInheritDoc() : bool |
89 |
90 |
91 | ### Class: \PHPDocsMD\DocInfoExtractor
92 |
93 | > Class that can extract information from a function/class comment
94 |
95 | | Visibility | Function |
96 | |:-----------|:---------|
97 | | public | applyInfoToEntity([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)/[\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $reflection, [\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo) $docInfo, [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity) $code) : void |
98 | | public | extractInfo([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)/[\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $reflection) : [\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo) |
99 |
100 |
101 | ### Class: \PHPDocsMD\FunctionEntity
102 |
103 | > Object describing a function
104 |
105 | | Visibility | Function |
106 | |:-----------|:---------|
107 | | public | getClass() : string |
108 | | public | getParams() : [\PHPDocsMD\ParamEntity](#class-phpdocsmdparamentity)[] |
109 | | public | getReturnType() : string |
110 | | public | getVisibility() : string |
111 | | public | hasParams() : bool |
112 | | public | isAbstract(bool $toggle=null) : bool |
113 | | public | isReturningNativeClass(bool $toggle=null) : bool |
114 | | public | isStatic(bool $toggle=null) : bool |
115 | | public | setClass(string $class) : void |
116 | | public | setParams([\PHPDocsMD\ParamEntity](#class-phpdocsmdparamentity)[] $params) : void |
117 | | public | setReturnType(string $returnType) : void |
118 | | public | setVisibility(string $visibility) : void |
119 |
120 | *This class extends [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)*
121 |
122 |
123 | ### Class: \PHPDocsMD\FunctionFinder
124 |
125 | > Find a specific function in a class or an array of classes
126 |
127 | | Visibility | Function |
128 | |:-----------|:---------|
129 | | public | find(string $methodName, string $className) : bool/[\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) |
130 | | public | findInClasses(string $methodName, array $classes) : bool/[\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) |
131 |
132 |
133 | ### Class: \PHPDocsMD\MDTableGenerator
134 |
135 | > Class that can create a markdown-formatted table describing class functions referred to via FunctionEntity objects
136 |
137 | ###### Example
138 | ```php
139 | openTable();
142 | foreach($classEntity->getFunctions() as $func) {
143 | $generator->addFunc( $func );
144 | }
145 | echo $generator->getTable();
146 | ```
147 |
148 | | Visibility | Function |
149 | |:-----------|:---------|
150 | | public | addFunc([\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) $func) : string
Generates a markdown formatted table row with information about given function. Then adds the row to the table and returns the markdown formatted string. |
151 | | public | appendExamplesToEndOfTable(bool $toggle) : void
All example comments found while generating the table will be appended to the end of the table. Set $toggle to false to prevent this behaviour |
152 | | public | doDeclareAbstraction(bool $toggle) : void
Toggle whether or not methods being abstract (or part of an interface) should be declared as abstract in the table |
153 | | public static | formatExampleComment(string $example) : string
Create a markdown-formatted code view out of an example comment |
154 | | public | getTable() : string |
155 | | public | openTable() : void
Begin generating a new markdown-formatted table |
156 |
157 |
158 | ### Class: \PHPDocsMD\ParamEntity
159 |
160 | > Object describing a function parameter
161 |
162 | | Visibility | Function |
163 | |:-----------|:---------|
164 | | public | getDefault() : boolean |
165 | | public | getNativeClassType() : string/null |
166 | | public | getType() : string |
167 | | public | setDefault(boolean $default) : void |
168 | | public | setType(string $type) : void |
169 |
170 | *This class extends [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)*
171 |
172 |
173 | ### Class: \PHPDocsMD\Reflector
174 |
175 | > Class that can compute ClassEntity objects out of real classes
176 |
177 | | Visibility | Function |
178 | |:-----------|:---------|
179 | | public | __construct(string $className, [\PHPDocsMD\FunctionFinder](#class-phpdocsmdfunctionfinder) $functionFinder=null, [\PHPDocsMD\DocInfoExtractor](#class-phpdocsmddocinfoextractor) $docInfoExtractor=null, [\PHPDocsMD\UseInspector](#class-phpdocsmduseinspector) $useInspector=null, [\PHPDocsMD\ClassEntityFactory](#class-phpdocsmdclassentityfactory) $classEntityFactory=null) : void |
180 | | public | getClassEntity() : [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) |
181 | | public static | getParamType([\ReflectionParameter](http://php.net/manual/en/class.reflectionparameter.php) $refParam) : string
Tries to find out if the type of the given parameter. Will return empty string if not possible. |
182 | | protected | createFunctionEntity([\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $method, [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) $class, array $useStatements) : bool/[\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) |
183 | | protected | shouldIgnoreFunction([\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo) $info, [\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $method, [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) $class) : bool |
184 | ###### Examples of Reflector::getParamType()
185 | ```php
186 | getMethods() as $method ) {
189 | foreach($method->getParameters() as $param) {
190 | $name = $param->getName();
191 | $type = Reflector::getParamType($param);
192 | printf("%s = %s\n", $name, $type);
193 | }
194 | }
195 | ```
196 |
197 | *This class implements [\PHPDocsMD\ReflectorInterface](#interface-phpdocsmdreflectorinterface)*
198 |
199 |
200 | ### Interface: \PHPDocsMD\ReflectorInterface
201 |
202 | > Interface for classes that can compute ClassEntity objects
203 |
204 | | Visibility | Function |
205 | |:-----------|:---------|
206 | | public | getClassEntity() : [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) |
207 |
208 |
209 | ### Class: \PHPDocsMD\UseInspector
210 |
211 | > Class that can extract all use statements in a file
212 |
213 | | Visibility | Function |
214 | |:-----------|:---------|
215 | | public | getUseStatements([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php) $reflectionClass) : array |
216 | | public | getUseStatementsInFile(string $filePath) : array |
217 | | public | getUseStatementsInString(string $content) : string[] |
218 |
219 |
220 | ### Class: \PHPDocsMD\Utils
221 |
222 | | Visibility | Function |
223 | |:-----------|:---------|
224 | | public static | getClassBaseName(string $fullClassName) : string |
225 | | public static | isClassReference(string $typeDeclaration) : bool |
226 | | public static | isNativeClassReference(mixed $typeDeclaration) : bool |
227 | | public static | sanitizeClassName(string $name) : string |
228 | | public static | sanitizeDeclaration(string $typeDeclaration, string $currentNameSpace, string $delimiter=`'|'`) : string |
229 |
230 |
231 | ### Class: \PHPDocsMD\Console\CLI
232 |
233 | > Command line interface used to extract markdown-formatted documentation from classes
234 |
235 | | Visibility | Function |
236 | |:-----------|:---------|
237 | | public | __construct() : void |
238 | | public | run(\Symfony\Component\Console\Input\InputInterface $input=null, \Symfony\Component\Console\Output\OutputInterface $output=null) : int |
239 |
240 | *This class extends \Symfony\Component\Console\Application*
241 |
242 |
243 | ### Class: \PHPDocsMD\Console\PHPDocsMDCommand
244 |
245 | > Console command used to extract markdown-formatted documentation from classes
246 |
247 | | Visibility | Function |
248 | |:-----------|:---------|
249 | | public | extractClassNameFromLine(string $type, string $line) : string |
250 | | protected | configure() : void |
251 | | protected | execute(\Symfony\Component\Console\Input\InputInterface $input, \Symfony\Component\Console\Output\OutputInterface $output) : int/null |
252 |
253 | *This class extends \Symfony\Component\Console\Command\Command*
254 |
255 | ## Table of contents
256 |
257 | - [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity)
258 | - [\PHPDocsMD\ClassEntityFactory](#class-phpdocsmdclassentityfactory)
259 | - [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)
260 | - [\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo)
261 | - [\PHPDocsMD\DocInfoExtractor](#class-phpdocsmddocinfoextractor)
262 | - [\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity)
263 | - [\PHPDocsMD\FunctionFinder](#class-phpdocsmdfunctionfinder)
264 | - [\PHPDocsMD\MDTableGenerator](#class-phpdocsmdmdtablegenerator)
265 | - [\PHPDocsMD\ParamEntity](#class-phpdocsmdparamentity)
266 | - [\PHPDocsMD\Reflector](#class-phpdocsmdreflector)
267 | - [\PHPDocsMD\ReflectorInterface (interface)](#interface-phpdocsmdreflectorinterface)
268 | - [\PHPDocsMD\UseInspector](#class-phpdocsmduseinspector)
269 | - [\PHPDocsMD\Utils](#class-phpdocsmdutils)
270 | - [\PHPDocsMD\Console\CLI](#class-phpdocsmdconsolecli)
271 | - [\PHPDocsMD\Console\PHPDocsMDCommand](#class-phpdocsmdconsolephpdocsmdcommand)
272 |
273 |
274 | ### Class: \PHPDocsMD\ClassEntity
275 |
276 | > Object describing a class or an interface
277 |
278 | | Visibility | Function |
279 | |:-----------|:---------|
280 | | public | generateAnchor() : string
Generates an anchor link out of the generated title (see generateTitle) |
281 | | public | generateTitle(string $format=`'%label%: %name% %extra%'`) : string
Generate a title describing the class this object is referring to |
282 | | public | getExtends() : string |
283 | | public | getFunctions() : [\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity)[] |
284 | | public | getInterfaces() : array |
285 | | public | hasIgnoreTag(bool $toggle=null) : bool |
286 | | public | isAbstract(bool $toggle=null) : bool |
287 | | public | isInterface(bool $toggle=null) : bool |
288 | | public | isNative(bool $toggle=null) : bool |
289 | | public | isSame(string/object $class) : bool
Check whether this object is referring to given class name or object instance |
290 | | public | setExtends(string $extends) : void |
291 | | public | setFunctions([\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity)[] $functions) : void |
292 | | public | setInterfaces(array $implements) : void |
293 | | public | setName(string $name) : void |
294 |
295 | *This class extends [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)*
296 |
297 |
298 | ### Class: \PHPDocsMD\ClassEntityFactory
299 |
300 | > Class capable of creating ClassEntity objects
301 |
302 | | Visibility | Function |
303 | |:-----------|:---------|
304 | | public | __construct([\PHPDocsMD\DocInfoExtractor](#class-phpdocsmddocinfoextractor) $docInfoExtractor) : void |
305 | | public | create([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php) $reflection) : mixed |
306 |
307 |
308 | ### Class: \PHPDocsMD\CodeEntity
309 |
310 | > Object describing a piece of code
311 |
312 | | Visibility | Function |
313 | |:-----------|:---------|
314 | | public | getDeprecationMessage() : string |
315 | | public | getDescription() : string |
316 | | public | getExample() : string |
317 | | public | getName() : string |
318 | | public | isDeprecated(bool $toggle=null) : void/bool |
319 | | public | setDeprecationMessage(string $deprecationMessage) : void |
320 | | public | setDescription(string $description) : void |
321 | | public | setExample(string $example) : void |
322 | | public | setName(string $name) : void |
323 |
324 |
325 | ### Class: \PHPDocsMD\DocInfo
326 |
327 | > Class containing information about a function/class that's being made available via a comment block
328 |
329 | | Visibility | Function |
330 | |:-----------|:---------|
331 | | public | __construct(array $data) : void |
332 | | public | getDeprecationMessage() : string |
333 | | public | getDescription() : string |
334 | | public | getExample() : string |
335 | | public | getParameterInfo(string $name) : array |
336 | | public | getParameters() : array |
337 | | public | getReturnType() : string |
338 | | public | shouldBeIgnored() : bool |
339 | | public | shouldInheritDoc() : bool |
340 |
341 |
342 | ### Class: \PHPDocsMD\DocInfoExtractor
343 |
344 | > Class that can extract information from a function/class comment
345 |
346 | | Visibility | Function |
347 | |:-----------|:---------|
348 | | public | applyInfoToEntity([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)/[\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $reflection, [\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo) $docInfo, [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity) $code) : void |
349 | | public | extractInfo([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)/[\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $reflection) : [\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo) |
350 |
351 |
352 | ### Class: \PHPDocsMD\FunctionEntity
353 |
354 | > Object describing a function
355 |
356 | | Visibility | Function |
357 | |:-----------|:---------|
358 | | public | getClass() : string |
359 | | public | getParams() : [\PHPDocsMD\ParamEntity](#class-phpdocsmdparamentity)[] |
360 | | public | getReturnType() : string |
361 | | public | getVisibility() : string |
362 | | public | hasParams() : bool |
363 | | public | isAbstract(bool $toggle=null) : bool |
364 | | public | isReturningNativeClass(bool $toggle=null) : bool |
365 | | public | isStatic(bool $toggle=null) : bool |
366 | | public | setClass(string $class) : void |
367 | | public | setParams([\PHPDocsMD\ParamEntity](#class-phpdocsmdparamentity)[] $params) : void |
368 | | public | setReturnType(string $returnType) : void |
369 | | public | setVisibility(string $visibility) : void |
370 |
371 | *This class extends [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)*
372 |
373 |
374 | ### Class: \PHPDocsMD\FunctionFinder
375 |
376 | > Find a specific function in a class or an array of classes
377 |
378 | | Visibility | Function |
379 | |:-----------|:---------|
380 | | public | find(string $methodName, string $className) : bool/[\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) |
381 | | public | findInClasses(string $methodName, array $classes) : bool/[\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) |
382 |
383 |
384 | ### Class: \PHPDocsMD\MDTableGenerator
385 |
386 | > Class that can create a markdown-formatted table describing class functions referred to via FunctionEntity objects
387 |
388 | ###### Example
389 | ```php
390 | openTable();
393 | foreach($classEntity->getFunctions() as $func) {
394 | $generator->addFunc( $func );
395 | }
396 | echo $generator->getTable();
397 | ```
398 |
399 | | Visibility | Function |
400 | |:-----------|:---------|
401 | | public | addFunc([\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) $func) : string
Generates a markdown formatted table row with information about given function. Then adds the row to the table and returns the markdown formatted string. |
402 | | public | appendExamplesToEndOfTable(bool $toggle) : void
All example comments found while generating the table will be appended to the end of the table. Set $toggle to false to prevent this behaviour |
403 | | public | doDeclareAbstraction(bool $toggle) : void
Toggle whether or not methods being abstract (or part of an interface) should be declared as abstract in the table |
404 | | public static | formatExampleComment(string $example) : string
Create a markdown-formatted code view out of an example comment |
405 | | public | getTable() : string |
406 | | public | openTable() : void
Begin generating a new markdown-formatted table |
407 |
408 |
409 | ### Class: \PHPDocsMD\ParamEntity
410 |
411 | > Object describing a function parameter
412 |
413 | | Visibility | Function |
414 | |:-----------|:---------|
415 | | public | getDefault() : boolean |
416 | | public | getNativeClassType() : string/null |
417 | | public | getType() : string |
418 | | public | setDefault(boolean $default) : void |
419 | | public | setType(string $type) : void |
420 |
421 | *This class extends [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)*
422 |
423 |
424 | ### Class: \PHPDocsMD\Reflector
425 |
426 | > Class that can compute ClassEntity objects out of real classes
427 |
428 | | Visibility | Function |
429 | |:-----------|:---------|
430 | | public | __construct(string $className, [\PHPDocsMD\FunctionFinder](#class-phpdocsmdfunctionfinder) $functionFinder=null, [\PHPDocsMD\DocInfoExtractor](#class-phpdocsmddocinfoextractor) $docInfoExtractor=null, [\PHPDocsMD\UseInspector](#class-phpdocsmduseinspector) $useInspector=null, [\PHPDocsMD\ClassEntityFactory](#class-phpdocsmdclassentityfactory) $classEntityFactory=null) : void |
431 | | public | getClassEntity() : [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) |
432 | | public static | getParamType([\ReflectionParameter](http://php.net/manual/en/class.reflectionparameter.php) $refParam) : string
Tries to find out if the type of the given parameter. Will return empty string if not possible. |
433 | | protected | createFunctionEntity([\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $method, [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) $class, array $useStatements) : bool/[\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) |
434 | | protected | shouldIgnoreFunction([\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo) $info, [\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $method, [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) $class) : bool |
435 | ###### Examples of Reflector::getParamType()
436 | ```php
437 | getMethods() as $method ) {
440 | foreach($method->getParameters() as $param) {
441 | $name = $param->getName();
442 | $type = Reflector::getParamType($param);
443 | printf("%s = %s\n", $name, $type);
444 | }
445 | }
446 | ```
447 |
448 | *This class implements [\PHPDocsMD\ReflectorInterface](#interface-phpdocsmdreflectorinterface)*
449 |
450 |
451 | ### Interface: \PHPDocsMD\ReflectorInterface
452 |
453 | > Interface for classes that can compute ClassEntity objects
454 |
455 | | Visibility | Function |
456 | |:-----------|:---------|
457 | | public | getClassEntity() : [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) |
458 |
459 |
460 | ### Class: \PHPDocsMD\UseInspector
461 |
462 | > Class that can extract all use statements in a file
463 |
464 | | Visibility | Function |
465 | |:-----------|:---------|
466 | | public | getUseStatements([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php) $reflectionClass) : array |
467 | | public | getUseStatementsInFile(string $filePath) : array |
468 | | public | getUseStatementsInString(string $content) : string[] |
469 |
470 |
471 | ### Class: \PHPDocsMD\Utils
472 |
473 | | Visibility | Function |
474 | |:-----------|:---------|
475 | | public static | getClassBaseName(string $fullClassName) : string |
476 | | public static | isClassReference(string $typeDeclaration) : bool |
477 | | public static | isNativeClassReference(mixed $typeDeclaration) : bool |
478 | | public static | sanitizeClassName(string $name) : string |
479 | | public static | sanitizeDeclaration(string $typeDeclaration, string $currentNameSpace, string $delimiter=`'|'`) : string |
480 |
481 |
482 | ### Class: \PHPDocsMD\Console\CLI
483 |
484 | > Command line interface used to extract markdown-formatted documentation from classes
485 |
486 | | Visibility | Function |
487 | |:-----------|:---------|
488 | | public | __construct() : void |
489 | | public | run(\Symfony\Component\Console\Input\InputInterface $input=null, \Symfony\Component\Console\Output\OutputInterface $output=null) : int |
490 |
491 | *This class extends \Symfony\Component\Console\Application*
492 |
493 |
494 | ### Class: \PHPDocsMD\Console\PHPDocsMDCommand
495 |
496 | > Console command used to extract markdown-formatted documentation from classes
497 |
498 | | Visibility | Function |
499 | |:-----------|:---------|
500 | | public | extractClassNameFromLine(string $type, string $line) : string |
501 | | protected | configure() : void |
502 | | protected | execute(\Symfony\Component\Console\Input\InputInterface $input, \Symfony\Component\Console\Output\OutputInterface $output) : int/null |
503 |
504 | *This class extends \Symfony\Component\Console\Command\Command*
505 |
506 | ## Table of contents
507 |
508 | - [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity)
509 | - [\PHPDocsMD\ClassEntityFactory](#class-phpdocsmdclassentityfactory)
510 | - [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)
511 | - [\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo)
512 | - [\PHPDocsMD\DocInfoExtractor](#class-phpdocsmddocinfoextractor)
513 | - [\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity)
514 | - [\PHPDocsMD\FunctionFinder](#class-phpdocsmdfunctionfinder)
515 | - [\PHPDocsMD\MDTableGenerator](#class-phpdocsmdmdtablegenerator)
516 | - [\PHPDocsMD\ParamEntity](#class-phpdocsmdparamentity)
517 | - [\PHPDocsMD\Reflector](#class-phpdocsmdreflector)
518 | - [\PHPDocsMD\ReflectorInterface (interface)](#interface-phpdocsmdreflectorinterface)
519 | - [\PHPDocsMD\UseInspector](#class-phpdocsmduseinspector)
520 | - [\PHPDocsMD\Utils](#class-phpdocsmdutils)
521 | - [\PHPDocsMD\Console\CLI](#class-phpdocsmdconsolecli)
522 | - [\PHPDocsMD\Console\PHPDocsMDCommand](#class-phpdocsmdconsolephpdocsmdcommand)
523 |
524 |
525 |
526 | ### Class: \PHPDocsMD\ClassEntity
527 |
528 | > Object describing a class or an interface
529 |
530 | | Visibility | Function |
531 | |:-----------|:---------|
532 | | public | generateAnchor() : string
Generates an anchor link out of the generated title (see generateTitle) |
533 | | public | generateTitle(string $format=`'%label%: %name% %extra%'`) : string
Generate a title describing the class this object is referring to |
534 | | public | getExtends() : string |
535 | | public | getFunctions() : [\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity)[] |
536 | | public | getInterfaces() : array |
537 | | public | hasIgnoreTag(bool $toggle=null) : bool |
538 | | public | isAbstract(bool $toggle=null) : bool |
539 | | public | isInterface(bool $toggle=null) : bool |
540 | | public | isNative(bool $toggle=null) : bool |
541 | | public | isSame(string/object $class) : bool
Check whether this object is referring to given class name or object instance |
542 | | public | setExtends(string $extends) : void |
543 | | public | setFunctions([\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity)[] $functions) : void |
544 | | public | setInterfaces(array $implements) : void |
545 | | public | setName(string $name) : void |
546 |
547 | *This class extends [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)*
548 |
549 |
550 |
551 | ### Class: \PHPDocsMD\ClassEntityFactory
552 |
553 | > Class capable of creating ClassEntity objects
554 |
555 | | Visibility | Function |
556 | |:-----------|:---------|
557 | | public | __construct([\PHPDocsMD\DocInfoExtractor](#class-phpdocsmddocinfoextractor) $docInfoExtractor) : void |
558 | | public | create([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php) $reflection) : mixed |
559 |
560 |
561 |
562 | ### Class: \PHPDocsMD\CodeEntity
563 |
564 | > Object describing a piece of code
565 |
566 | | Visibility | Function |
567 | |:-----------|:---------|
568 | | public | getDeprecationMessage() : string |
569 | | public | getDescription() : string |
570 | | public | getExample() : string |
571 | | public | getName() : string |
572 | | public | isDeprecated(bool $toggle=null) : void/bool |
573 | | public | setDeprecationMessage(string $deprecationMessage) : void |
574 | | public | setDescription(string $description) : void |
575 | | public | setExample(string $example) : void |
576 | | public | setName(string $name) : void |
577 |
578 |
579 |
580 | ### Class: \PHPDocsMD\DocInfo
581 |
582 | > Class containing information about a function/class that's being made available via a comment block
583 |
584 | | Visibility | Function |
585 | |:-----------|:---------|
586 | | public | __construct(array $data) : void |
587 | | public | getDeprecationMessage() : string |
588 | | public | getDescription() : string |
589 | | public | getExample() : string |
590 | | public | getParameterInfo(string $name) : array |
591 | | public | getParameters() : array |
592 | | public | getReturnType() : string |
593 | | public | shouldBeIgnored() : bool |
594 | | public | shouldInheritDoc() : bool |
595 |
596 |
597 |
598 | ### Class: \PHPDocsMD\DocInfoExtractor
599 |
600 | > Class that can extract information from a function/class comment
601 |
602 | | Visibility | Function |
603 | |:-----------|:---------|
604 | | public | applyInfoToEntity([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)/[\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $reflection, [\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo) $docInfo, [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity) $code) : void |
605 | | public | extractInfo([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)/[\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $reflection) : [\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo) |
606 |
607 |
608 |
609 | ### Class: \PHPDocsMD\FunctionEntity
610 |
611 | > Object describing a function
612 |
613 | | Visibility | Function |
614 | |:-----------|:---------|
615 | | public | getClass() : string |
616 | | public | getParams() : [\PHPDocsMD\ParamEntity](#class-phpdocsmdparamentity)[] |
617 | | public | getReturnType() : string |
618 | | public | getVisibility() : string |
619 | | public | hasParams() : bool |
620 | | public | isAbstract(bool $toggle=null) : bool |
621 | | public | isReturningNativeClass(bool $toggle=null) : bool |
622 | | public | isStatic(bool $toggle=null) : bool |
623 | | public | setClass(string $class) : void |
624 | | public | setParams([\PHPDocsMD\ParamEntity](#class-phpdocsmdparamentity)[] $params) : void |
625 | | public | setReturnType(string $returnType) : void |
626 | | public | setVisibility(string $visibility) : void |
627 |
628 | *This class extends [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)*
629 |
630 |
631 |
632 | ### Class: \PHPDocsMD\FunctionFinder
633 |
634 | > Find a specific function in a class or an array of classes
635 |
636 | | Visibility | Function |
637 | |:-----------|:---------|
638 | | public | find(string $methodName, string $className) : bool/[\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) |
639 | | public | findInClasses(string $methodName, array $classes) : bool/[\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) |
640 |
641 |
642 |
643 | ### Class: \PHPDocsMD\MDTableGenerator
644 |
645 | > Class that can create a markdown-formatted table describing class functions referred to via FunctionEntity objects
646 |
647 | ###### Example
648 | ```php
649 | openTable();
652 | foreach($classEntity->getFunctions() as $func) {
653 | $generator->addFunc( $func );
654 | }
655 | echo $generator->getTable();
656 | ```
657 |
658 | | Visibility | Function |
659 | |:-----------|:---------|
660 | | public | addFunc([\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) $func) : string
Generates a markdown formatted table row with information about given function. Then adds the row to the table and returns the markdown formatted string. |
661 | | public | appendExamplesToEndOfTable(bool $toggle) : void
All example comments found while generating the table will be appended to the end of the table. Set $toggle to false to prevent this behaviour |
662 | | public | doDeclareAbstraction(bool $toggle) : void
Toggle whether or not methods being abstract (or part of an interface) should be declared as abstract in the table |
663 | | public static | formatExampleComment(string $example) : string
Create a markdown-formatted code view out of an example comment |
664 | | public | getTable() : string |
665 | | public | openTable() : void
Begin generating a new markdown-formatted table |
666 |
667 |
668 |
669 | ### Class: \PHPDocsMD\ParamEntity
670 |
671 | > Object describing a function parameter
672 |
673 | | Visibility | Function |
674 | |:-----------|:---------|
675 | | public | getDefault() : boolean |
676 | | public | getNativeClassType() : string/null |
677 | | public | getType() : string |
678 | | public | setDefault(boolean $default) : void |
679 | | public | setType(string $type) : void |
680 |
681 | *This class extends [\PHPDocsMD\CodeEntity](#class-phpdocsmdcodeentity)*
682 |
683 |
684 |
685 | ### Class: \PHPDocsMD\Reflector
686 |
687 | > Class that can compute ClassEntity objects out of real classes
688 |
689 | | Visibility | Function |
690 | |:-----------|:---------|
691 | | public | __construct(string $className, [\PHPDocsMD\FunctionFinder](#class-phpdocsmdfunctionfinder) $functionFinder=null, [\PHPDocsMD\DocInfoExtractor](#class-phpdocsmddocinfoextractor) $docInfoExtractor=null, [\PHPDocsMD\UseInspector](#class-phpdocsmduseinspector) $useInspector=null, [\PHPDocsMD\ClassEntityFactory](#class-phpdocsmdclassentityfactory) $classEntityFactory=null) : void |
692 | | public | getClassEntity() : [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) |
693 | | public static | getParamType([\ReflectionParameter](http://php.net/manual/en/class.reflectionparameter.php) $refParam) : string
Tries to find out if the type of the given parameter. Will return empty string if not possible. |
694 | | protected | createFunctionEntity([\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $method, [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) $class, array $useStatements) : bool/[\PHPDocsMD\FunctionEntity](#class-phpdocsmdfunctionentity) |
695 | | protected | shouldIgnoreFunction([\PHPDocsMD\DocInfo](#class-phpdocsmddocinfo) $info, [\ReflectionMethod](http://php.net/manual/en/class.reflectionmethod.php) $method, [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) $class) : bool |
696 | ###### Examples of Reflector::getParamType()
697 | ```php
698 | getMethods() as $method ) {
701 | foreach($method->getParameters() as $param) {
702 | $name = $param->getName();
703 | $type = Reflector::getParamType($param);
704 | printf("%s = %s\n", $name, $type);
705 | }
706 | }
707 | ```
708 |
709 | *This class implements [\PHPDocsMD\ReflectorInterface](#interface-phpdocsmdreflectorinterface)*
710 |
711 |
712 |
713 | ### Interface: \PHPDocsMD\ReflectorInterface
714 |
715 | > Interface for classes that can compute ClassEntity objects
716 |
717 | | Visibility | Function |
718 | |:-----------|:---------|
719 | | public | getClassEntity() : [\PHPDocsMD\ClassEntity](#class-phpdocsmdclassentity) |
720 |
721 |
722 |
723 | ### Class: \PHPDocsMD\UseInspector
724 |
725 | > Class that can extract all use statements in a file
726 |
727 | | Visibility | Function |
728 | |:-----------|:---------|
729 | | public | getUseStatements([\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php) $reflectionClass) : array |
730 | | public | getUseStatementsInFile(string $filePath) : array |
731 | | public | getUseStatementsInString(string $content) : string[] |
732 |
733 |
734 |
735 | ### Class: \PHPDocsMD\Utils
736 |
737 | | Visibility | Function |
738 | |:-----------|:---------|
739 | | public static | getClassBaseName(string $fullClassName) : string |
740 | | public static | isClassReference(string $typeDeclaration) : bool |
741 | | public static | isNativeClassReference(mixed $typeDeclaration) : bool |
742 | | public static | sanitizeClassName(string $name) : string |
743 | | public static | sanitizeDeclaration(string $typeDeclaration, string $currentNameSpace, string $delimiter=`'|'`) : string |
744 |
745 |
746 |
747 | ### Class: \PHPDocsMD\Console\CLI
748 |
749 | > Command line interface used to extract markdown-formatted documentation from classes
750 |
751 | | Visibility | Function |
752 | |:-----------|:---------|
753 | | public | __construct() : void |
754 | | public | run(\Symfony\Component\Console\Input\InputInterface $input=null, \Symfony\Component\Console\Output\OutputInterface $output=null) : int |
755 |
756 | *This class extends \Symfony\Component\Console\Application*
757 |
758 |
759 |
760 | ### Class: \PHPDocsMD\Console\PHPDocsMDCommand
761 |
762 | > Console command used to extract markdown-formatted documentation from classes
763 |
764 | | Visibility | Function |
765 | |:-----------|:---------|
766 | | public | extractClassNameFromLine(string $type, string $line) : string |
767 | | protected | configure() : void |
768 | | protected | execute(\Symfony\Component\Console\Input\InputInterface $input, \Symfony\Component\Console\Output\OutputInterface $output) : int/null |
769 |
770 | *This class extends \Symfony\Component\Console\Command\Command*
771 |
772 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/ClassEntity.php:
--------------------------------------------------------------------------------
1 | abstract;
64 | } else {
65 | return $this->abstract = (bool)$toggle;
66 | }
67 | }
68 |
69 | /**
70 | * @param bool $toggle
71 | * @return bool
72 | */
73 | public function hasIgnoreTag($toggle=null)
74 | {
75 | if( $toggle === null ) {
76 | return $this->hasIgnoreTag;
77 | } else {
78 | return $this->hasIgnoreTag = (bool)$toggle;
79 | }
80 | }
81 |
82 | /**
83 | * @param bool $toggle
84 | * @return bool
85 | */
86 | public function hasInternalTag($toggle = null)
87 | {
88 | if ($toggle === null) {
89 | return $this->hasInternalTag;
90 | } else {
91 | return $this->hasInternalTag = (bool)$toggle;
92 | }
93 | }
94 |
95 | /**
96 | * @param bool $toggle
97 | * @return bool
98 | */
99 | public function isInterface($toggle=null)
100 | {
101 | if( $toggle === null ) {
102 | return $this->isInterface;
103 | } else {
104 | return $this->isInterface = (bool)$toggle;
105 | }
106 | }
107 |
108 | /**
109 | * @param bool $toggle
110 | * @return bool
111 | */
112 | public function isNative($toggle=null)
113 | {
114 | if( $toggle === null ) {
115 | return $this->isNative;
116 | } else {
117 | return $this->isNative = (bool)$toggle;
118 | }
119 | }
120 |
121 | /**
122 | * @param string $extends
123 | */
124 | public function setExtends($extends)
125 | {
126 | $this->extends = Utils::sanitizeClassName($extends);
127 | }
128 |
129 | /**
130 | * @return string
131 | */
132 | public function getExtends()
133 | {
134 | return $this->extends;
135 | }
136 |
137 | /**
138 | * @param \PHPDocsMD\FunctionEntity[] $functions
139 | */
140 | public function setFunctions(array $functions)
141 | {
142 | $this->functions = $functions;
143 | }
144 |
145 | /**
146 | * @param array $see
147 | */
148 | public function setSee(array $see)
149 | {
150 | $this->see = [];
151 | foreach($see as $i) {
152 | $this->see[] = $i;
153 | }
154 | }
155 |
156 | /**
157 | * @param array $implements
158 | */
159 | public function setInterfaces(array $implements)
160 | {
161 | $this->interfaces = [];
162 | foreach($implements as $interface) {
163 | $this->interfaces[] = Utils::sanitizeClassName($interface);
164 | }
165 | }
166 |
167 | /**
168 | * @return array
169 | */
170 | public function getInterfaces()
171 | {
172 | return $this->interfaces;
173 | }
174 |
175 | /**
176 | * @return array
177 | */
178 | public function getSee()
179 | {
180 | return $this->see;
181 | }
182 |
183 | /**
184 | * @return \PHPDocsMD\FunctionEntity[]
185 | */
186 | public function getFunctions()
187 | {
188 | return $this->functions;
189 | }
190 |
191 | /**
192 | * @param string $name
193 | */
194 | function setName($name)
195 | {
196 | parent::setName(Utils::sanitizeClassName($name));
197 | }
198 |
199 | /**
200 | * Check whether this object is referring to given class name or object instance
201 | * @param string|object $class
202 | * @return bool
203 | */
204 | function isSame($class)
205 | {
206 | $className = is_object($class) ? get_class($class) : $class;
207 | return Utils::sanitizeClassName($className) == $this->getName();
208 | }
209 |
210 | /**
211 | * Generate a title describing the class this object is referring to
212 | * @param string $format
213 | * @return string
214 | */
215 | function generateTitle($format='%label%: %name% %extra%')
216 | {
217 | $translate = [
218 | '%label%' => $this->isInterface() ? 'Interface' : 'Class',
219 | '%name%' => substr_count($this->getName(), '\\') == 1 ? substr($this->getName(), 1) : $this->getName(),
220 | '%extra%' => ''
221 | ];
222 |
223 | if( strpos($format, '%label%') === false ) {
224 | if( $this->isInterface() )
225 | $translate['%extra%'] = '(interface)';
226 | elseif( $this->isAbstract() )
227 | $translate['%extra%'] = '(abstract)';
228 | } else {
229 | $translate['%extra%'] = $this->isAbstract() && !$this->isInterface() ? '(abstract)' : '';
230 | }
231 |
232 | return trim(strtr($format, $translate));
233 | }
234 |
235 | /**
236 | * Generates an anchor link out of the generated title (see generateTitle)
237 | * @return string
238 | */
239 | function generateAnchor()
240 | {
241 | $title = $this->generateTitle();
242 | return strtolower(str_replace([':', ' ', '\\', '(', ')'], ['', '-', '', '', ''], $title));
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/ClassEntityFactory.php:
--------------------------------------------------------------------------------
1 | docInfoExtractor = $docInfoExtractor;
21 | }
22 |
23 | public function create(\ReflectionClass $reflection)
24 | {
25 | $class = new ClassEntity();
26 | $docInfo = $this->docInfoExtractor->extractInfo($reflection);
27 | $this->docInfoExtractor->applyInfoToEntity($reflection, $docInfo, $class);
28 | $class->isInterface($reflection->isInterface());
29 | $class->isAbstract($reflection->isAbstract());
30 | $class->setInterfaces(array_keys($reflection->getInterfaces()));
31 | $class->hasIgnoreTag($docInfo->shouldBeIgnored());
32 | $class->hasInternalTag($docInfo->isInternal());
33 |
34 | if ($reflection->getParentClass()) {
35 | $class->setExtends($reflection->getParentClass()->getName());
36 | }
37 |
38 | return $class;
39 | }
40 |
41 | }
--------------------------------------------------------------------------------
/src/PHPDocsMD/CodeEntity.php:
--------------------------------------------------------------------------------
1 | isDeprecated;
50 | } else {
51 | return $this->isDeprecated = (bool)$toggle;
52 | }
53 | }
54 |
55 | /**
56 | * @param bool $toggle
57 | * @return bool|null
58 | */
59 | public function isInternal($toggle=null)
60 | {
61 | if ($toggle === null) {
62 | return $this->isInternal;
63 | } else {
64 | return $this->isInternal = (bool)$toggle;
65 | }
66 | }
67 |
68 | /**
69 | * @param string $description
70 | */
71 | public function setDescription($description)
72 | {
73 | $this->description = $description;
74 | }
75 |
76 | /**
77 | * @return string
78 | */
79 | public function getDescription()
80 | {
81 | return $this->description;
82 | }
83 |
84 | /**
85 | * @param string $name
86 | */
87 | public function setName($name)
88 | {
89 | $this->name = $name;
90 | }
91 |
92 | /**
93 | * @return string
94 | */
95 | public function getName()
96 | {
97 | return $this->name;
98 | }
99 |
100 | /**
101 | * @param string $deprecationMessage
102 | */
103 | public function setDeprecationMessage($deprecationMessage)
104 | {
105 | $this->deprecationMessage = $deprecationMessage;
106 | }
107 |
108 | /**
109 | * @return string
110 | */
111 | public function getDeprecationMessage()
112 | {
113 | return $this->deprecationMessage;
114 | }
115 |
116 | /**
117 | * @param string $example
118 | */
119 | public function setExample($example)
120 | {
121 | $this->example = $example;
122 | }
123 |
124 | /**
125 | * @return string
126 | */
127 | public function getExample()
128 | {
129 | return $this->example;
130 | }
131 | }
--------------------------------------------------------------------------------
/src/PHPDocsMD/Console/CLI.php:
--------------------------------------------------------------------------------
1 | version);
19 | }
20 |
21 | /**
22 | * @param \Symfony\Component\Console\Input\InputInterface $input
23 | * @param \Symfony\Component\Console\Input\OutputInterface $output
24 | * @return int
25 | */
26 | public function run(InputInterface $input=null, OutputInterface $output=null)
27 | {
28 | $this->add(new PHPDocsMDCommand());
29 | return parent::run($input, $output);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/Console/PHPDocsMDCommand.php:
--------------------------------------------------------------------------------
1 | memory[$name]) ) {
50 | $reflector = new Reflector($name);
51 | if ( ! empty($this->visibilityFilter)) {
52 | $reflector->setVisibilityFilter($this->visibilityFilter);
53 | }
54 | if ( ! empty($this->methodRegex)) {
55 | $reflector->setMethodRegex($this->methodRegex);
56 | }
57 | $this->memory[$name] = $reflector->getClassEntity();
58 | }
59 | return $this->memory[$name];
60 | }
61 |
62 | protected function configure()
63 | {
64 | $this
65 | ->setName('generate')
66 | ->setDescription('Get docs for given class/source directory)')
67 | ->addArgument(
68 | self::ARG_CLASS,
69 | InputArgument::REQUIRED,
70 | 'Class or source directory'
71 | )
72 | ->addOption(
73 | self::OPT_BOOTSTRAP,
74 | 'b',
75 | InputOption::VALUE_REQUIRED,
76 | 'File to be included before generating documentation'
77 | )
78 | ->addOption(
79 | self::OPT_IGNORE,
80 | 'i',
81 | InputOption::VALUE_REQUIRED,
82 | 'Directories to ignore',
83 | ''
84 | )
85 | ->addOption(
86 | self::OPT_VISIBILITY,
87 | null,
88 | InputOption::VALUE_OPTIONAL,
89 | 'The visibility of the methods to import, a comma-separated list.',
90 | ''
91 | )
92 | ->addOption(
93 | self::OPT_METHOD_REGEX,
94 | null,
95 | InputOption::VALUE_OPTIONAL,
96 | 'The full regular expression methods should match to be included in the output.',
97 | ''
98 | )
99 | ->addOption(
100 | self::OPT_TABLE_GENERATOR,
101 | null,
102 | InputOption::VALUE_OPTIONAL,
103 | 'The slug of a supported table generator class or a fully qualified TableGenerator interface implementation class name.',
104 | 'default'
105 | )
106 | ->addOption(
107 | self::OPT_SEE,
108 | null,
109 | InputOption::VALUE_NONE,
110 | 'Include @see in generated markdown'
111 | )
112 | ->addOption(
113 | self::OPT_NO_INTERNAL,
114 | null,
115 | InputOption::VALUE_NONE,
116 | 'Ignore entities marked @internal'
117 | );
118 | }
119 |
120 | /**
121 | * @param InputInterface $input
122 | * @param OutputInterface $output
123 | * @return int|null
124 | * @throws \InvalidArgumentException
125 | */
126 | protected function execute(InputInterface $input, OutputInterface $output)
127 | {
128 |
129 | $classes = $input->getArgument(self::ARG_CLASS);
130 | $bootstrap = $input->getOption(self::OPT_BOOTSTRAP);
131 | $ignore = explode(',', $input->getOption(self::OPT_IGNORE));
132 | $this->visibilityFilter = empty($input->getOption(self::OPT_VISIBILITY))
133 | ? ['public', 'protected', 'abstract', 'final']
134 | : array_map('trim', preg_split('/\\s*,\\s*/', $input->getOption(self::OPT_VISIBILITY)));
135 | $this->methodRegex = $input->getOption(self::OPT_METHOD_REGEX) ?: false;
136 | $includeSee = $input->getOption(self::OPT_SEE);
137 | $noInternal = $input->getOption(self::OPT_NO_INTERNAL);
138 | $requestingOneClass = false;
139 |
140 | if( $bootstrap ) {
141 | require_once strpos($bootstrap,'/') === 0 ? $bootstrap : getcwd().'/'.$bootstrap;
142 | }
143 |
144 | $classCollection = [];
145 | if( strpos($classes, ',') !== false ) {
146 | foreach(explode(',', $classes) as $class) {
147 | if( class_exists($class) || interface_exists($class) || trait_exists($class) )
148 | $classCollection[0][] = $class;
149 | }
150 | }
151 | elseif( class_exists($classes) || interface_exists($classes) || trait_exists($classes) ) {
152 | $classCollection[] = array($classes);
153 | $requestingOneClass = true;
154 | } elseif( is_dir($classes) ) {
155 | $classCollection = $this->findClassesInDir($classes, [], $ignore);
156 | } else {
157 | throw new \InvalidArgumentException('Given input is neither a class nor a source directory');
158 | }
159 |
160 | $tableGeneratorSlug = $input->getOption(self::OPT_TABLE_GENERATOR);
161 | $tableGenerator = $this->buildTableGenerator($tableGeneratorSlug);
162 |
163 | $tableOfContent = [];
164 | $body = [];
165 | $classLinks = [];
166 |
167 | foreach($classCollection as $ns => $classes) {
168 | foreach($classes as $className) {
169 | $class = $this->getClassEntity($className);
170 |
171 | if ($class->hasIgnoreTag()
172 | || ($class->hasInternalTag() && $noInternal)) {
173 | continue;
174 | }
175 |
176 | // Add to tbl of contents
177 | $tableOfContent[] = sprintf('- [%s](#%s)', $class->generateTitle('%name% %extra%'), $class->generateAnchor());
178 |
179 | $classLinks[$class->getName()] = '#'.$class->generateAnchor();
180 |
181 | // generate function table
182 | $tableGenerator->openTable();
183 | $tableGenerator->doDeclareAbstraction(!$class->isInterface());
184 | foreach($class->getFunctions() as $func) {
185 | if ($func->isInternal() && $noInternal) {
186 | continue;
187 | }
188 | if ($func->isReturningNativeClass()) {
189 | $classLinks[$func->getReturnType()] = 'http://php.net/manual/en/class.'.
190 | strtolower(str_replace(array('[]', '\\'), '', $func->getReturnType())).
191 | '.php';
192 | }
193 | foreach($func->getParams() as $param) {
194 | if ($param->getNativeClassType()) {
195 | $classLinks[$param->getNativeClassType()] = 'http://php.net/manual/en/class.'.
196 | strtolower(str_replace(array('[]', '\\'), '', $param->getNativeClassType())).
197 | '.php';
198 | }
199 | }
200 | $tableGenerator->addFunc($func, $includeSee);
201 | }
202 |
203 | $docs = ($requestingOneClass ? '':'
'.PHP_EOL);
204 |
205 | if( $class->isDeprecated() ) {
206 | $docs .= '### '.$class->generateTitle().''.PHP_EOL.PHP_EOL.
207 | '> **DEPRECATED** '.$class->getDeprecationMessage().PHP_EOL.PHP_EOL;
208 | }
209 | else {
210 | $docs .= '### '.$class->generateTitle().PHP_EOL.PHP_EOL;
211 | if( $class->getDescription() )
212 | $docs .= '> '.$class->getDescription().PHP_EOL.PHP_EOL;
213 | }
214 |
215 | if ($includeSee && $seeArray = $class->getSee()) {
216 | foreach ($seeArray as $see) {
217 | $docs .= 'See ' . $see . '
' . PHP_EOL;
218 | }
219 | $docs .= PHP_EOL;
220 | }
221 |
222 | if( $example = $class->getExample() ) {
223 | $docs .= '###### Example' . PHP_EOL . MDTableGenerator::formatExampleComment($example) .PHP_EOL.PHP_EOL;
224 | }
225 |
226 | $docs .= $tableGenerator->getTable().PHP_EOL;
227 |
228 | if( $class->getExtends() ) {
229 | $link = $class->getExtends();
230 | if( $anchor = $this->getAnchorFromClassCollection($classCollection, $class->getExtends()) ) {
231 | $link = sprintf('[%s](#%s)', $link, $anchor);
232 | }
233 |
234 | $docs .= PHP_EOL.'*This class extends '.$link.'*'.PHP_EOL;
235 | }
236 |
237 | if( $interfaces = $class->getInterfaces() ) {
238 | $interfaceNames = [];
239 | foreach($interfaces as $interface) {
240 | $anchor = $this->getAnchorFromClassCollection($classCollection, $interface);
241 | $interfaceNames[] = $anchor ? sprintf('[%s](#%s)', $interface, $anchor) : $interface;
242 | }
243 | $docs .= PHP_EOL.'*This class implements '.implode(', ', $interfaceNames).'*'.PHP_EOL;
244 | }
245 |
246 | $body[] = $docs;
247 | }
248 | }
249 |
250 | if( empty($tableOfContent) ) {
251 | throw new \InvalidArgumentException('No classes found');
252 | } elseif( !$requestingOneClass ) {
253 | $output->writeln('## Table of contents'.PHP_EOL);
254 | $output->writeln(implode(PHP_EOL, $tableOfContent));
255 | }
256 |
257 | // Convert references to classes into links
258 | asort($classLinks);
259 | $classLinks = array_reverse($classLinks, true);
260 | $docString = implode(PHP_EOL, $body);
261 | foreach($classLinks as $className => $url) {
262 | $link = sprintf('[%s](%s)', $className, $url);
263 | $find = array(''.$className, '/'.$className);
264 | $replace = array(''.$link, '/'.$link);
265 | $docString = str_replace($find, $replace, $docString);
266 | }
267 |
268 | $output->writeln(PHP_EOL.$docString);
269 |
270 | return 0;
271 | }
272 |
273 | /**
274 | * @param $coll
275 | * @param $find
276 | * @return bool|string
277 | */
278 | private function getAnchorFromClassCollection($coll, $find)
279 | {
280 | foreach($coll as $ns => $classes) {
281 | foreach($classes as $className) {
282 | if( $className == $find ) {
283 | return $this->getClassEntity($className)->generateAnchor();
284 | }
285 | }
286 | }
287 | return false;
288 | }
289 |
290 | /**
291 | * @param $file
292 | * @return array
293 | */
294 | private function findClassInFile($file)
295 | {
296 | $ns = '';
297 | $class = false;
298 | foreach(explode(PHP_EOL, file_get_contents($file)) as $line) {
299 | if ( strpos($line, '*') === false ) {
300 | if( strpos($line, 'namespace') !== false ) {
301 | $ns = trim(current(array_slice(explode('namespace', $line), 1)), '; ');
302 | $ns = Utils::sanitizeClassName($ns);
303 | } elseif( strpos($line, 'class') !== false ) {
304 | $class = $this->extractClassNameFromLine('class', $line);
305 | break;
306 | } elseif( strpos($line, 'interface') !== false ) {
307 | $class = $this->extractClassNameFromLine('interface', $line);
308 | break;
309 | }
310 | }
311 | }
312 | return $class ? array($ns, $ns .'\\'. $class) : array(false, false);
313 | }
314 |
315 | /**
316 | * @param string $type
317 | * @param string $line
318 | * @return string
319 | */
320 | function extractClassNameFromLine($type, $line)
321 | {
322 | $class = trim(current(array_slice(explode($type, $line), 1)), '; ');
323 | return trim(current(explode(' ', $class)));
324 | }
325 |
326 | /**
327 | * @param $dir
328 | * @param array $collection
329 | * @param array $ignores
330 | * @return array
331 | */
332 | private function findClassesInDir($dir, $collection=[], $ignores=[])
333 | {
334 | foreach(new \FilesystemIterator($dir) as $f) {
335 | /** @var \SplFileInfo $f */
336 | if( $f->isFile() && !$f->isLink() ) {
337 | list($ns, $className) = $this->findClassInFile($f->getRealPath());
338 | if( $className && (class_exists($className, true) || interface_exists($className) || trait_exists($className)) ) {
339 | $collection[$ns][] = $className;
340 | }
341 | } elseif( $f->isDir() && !$f->isLink() && !$this->shouldIgnoreDirectory($f->getFilename(), $ignores) ) {
342 | $collection = $this->findClassesInDir($f->getRealPath(), $collection);
343 | }
344 | }
345 | ksort($collection);
346 | return $collection;
347 | }
348 |
349 | /**
350 | * @param $dirName
351 | * @param $ignores
352 | * @return bool
353 | */
354 | private function shouldIgnoreDirectory($dirName, $ignores) {
355 | foreach($ignores as $dir) {
356 | $dir = trim($dir);
357 | if( !empty($dir) && substr($dirName, -1 * strlen($dir)) == $dir ) {
358 | return true;
359 | }
360 | }
361 | return false;
362 | }
363 |
364 | protected function buildTableGenerator($tableGeneratorSlug = 'default')
365 | {
366 | if (class_exists($tableGeneratorSlug)) {
367 | if (!in_array(TableGenerator::class, class_implements($tableGeneratorSlug), true)) {
368 | throw new \InvalidArgumentException('The table generator class should implement the ' .
369 | TableGenerator::class . ' interface.');
370 | }
371 |
372 | return new $tableGeneratorSlug();
373 | }
374 |
375 | $map = [
376 | 'default' => MDTableGenerator::class,
377 | ];
378 |
379 | $class = isset($map[$tableGeneratorSlug]) ? $map[$tableGeneratorSlug] : $map['default'];
380 |
381 | return new $class;
382 | }
383 |
384 | }
385 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/DocInfo.php:
--------------------------------------------------------------------------------
1 | data = array_merge([
24 | 'return' => '',
25 | 'params' => [],
26 | 'description' => '',
27 | 'example' => false,
28 | 'deprecated' => false,
29 | 'see' => []
30 | ], $data);
31 | }
32 |
33 | /**
34 | * @return string
35 | */
36 | public function getReturnType()
37 | {
38 | return $this->data['return'];
39 | }
40 |
41 | /**
42 | * @return array
43 | */
44 | public function getParameters()
45 | {
46 | return $this->data['params'];
47 | }
48 |
49 | /**
50 | * @param string $name
51 | * @return array
52 | */
53 | public function getParameterInfo($name)
54 | {
55 | if (isset($this->data['params'][$name])) {
56 | return $this->data['params'][$name];
57 | }
58 | return [];
59 | }
60 |
61 | /**
62 | * @return string
63 | */
64 | public function getExample()
65 | {
66 | return $this->data['example'];
67 | }
68 |
69 | /**
70 | * @return string
71 | */
72 | public function getDescription()
73 | {
74 | return $this->data['description'];
75 | }
76 |
77 | /**
78 | * @return string
79 | */
80 | public function getDeprecationMessage()
81 | {
82 | return $this->data['deprecated'];
83 | }
84 |
85 | /**
86 | * @return array
87 | */
88 | public function getSee()
89 | {
90 | return $this->data['see'];
91 | }
92 |
93 | /**
94 | * @return bool
95 | */
96 | public function shouldInheritDoc()
97 | {
98 | return isset($this->data['inheritDoc']) || isset($this->data['inheritdoc']);
99 | }
100 |
101 | /**
102 | * @return bool
103 | */
104 | public function shouldBeIgnored()
105 | {
106 | return isset($this->data['ignore']);
107 | }
108 |
109 | /**
110 | * @return bool
111 | */
112 | public function isInternal()
113 | {
114 | return isset($this->data['internal']);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/DocInfoExtractor.php:
--------------------------------------------------------------------------------
1 | getCleanDocComment($reflection);
17 | $data = $this->extractInfoFromComment($comment, $reflection);
18 | return new DocInfo($data);
19 | }
20 |
21 | /**
22 | * @param \ReflectionClass|\ReflectionMethod $reflection
23 | * @param DocInfo $docInfo
24 | * @param CodeEntity $code
25 | */
26 | public function applyInfoToEntity($reflection, DocInfo $docInfo, CodeEntity $code)
27 | {
28 | $code->setName($reflection->getName());
29 | $code->setDescription($docInfo->getDescription());
30 | $code->setExample($docInfo->getExample());
31 | $code->setSee($docInfo->getSee());
32 | $code->isInternal($docInfo->isInternal());
33 |
34 | if ($docInfo->getDeprecationMessage()) {
35 | $code->isDeprecated(true);
36 | $code->setDeprecationMessage($docInfo->getDeprecationMessage());
37 | }
38 | }
39 |
40 | /**
41 | * @param \ReflectionClass $reflection
42 | * @return string
43 | */
44 | private function getCleanDocComment($reflection)
45 | {
46 | $comment = str_replace(['/*', '*/'], '', $reflection->getDocComment());
47 | return trim(trim(preg_replace('/([\s|^]\*\s)/', '', $comment)), '*');
48 | }
49 |
50 | /**
51 | * @param string $comment
52 | * @param string $current_tag
53 | * @param \ReflectionMethod|\ReflectionClass $reflection
54 | * @return array
55 | */
56 | private function extractInfoFromComment($comment, $reflection, $current_tag='description')
57 | {
58 | $currentNamespace = $this->getNameSpace($reflection);
59 | $tags = [$current_tag=>''];
60 |
61 | foreach(explode(PHP_EOL, $comment) as $line) {
62 |
63 | if( $current_tag != 'example' )
64 | $line = trim($line);
65 |
66 | $words = $this->getWordsFromLine($line);
67 | if( empty($words) )
68 | continue;
69 |
70 | if( strpos($words[0], '@') === false ) {
71 | // Append to tag
72 | $joinWith = $current_tag == 'example' ? PHP_EOL : ' ';
73 | $tags[$current_tag] .= $joinWith . $line;
74 | }
75 | elseif( $words[0] == '@param' ) {
76 | // Get parameter declaration
77 | if( $paramData = $this->figureOutParamDeclaration($words, $currentNamespace) ) {
78 | list($name, $data) = $paramData;
79 | $tags['params'][$name] = $data;
80 | }
81 | }
82 | elseif( $words[0] == '@see' ) {
83 | $tags['see'][] = $this->figureOutSeeDeclaration($words);
84 | }
85 | else {
86 | // Start new tag
87 | $current_tag = substr($words[0], 1);
88 | array_splice($words, 0 ,1);
89 | if( empty($tags[$current_tag]) ) {
90 | $tags[$current_tag] = '';
91 | }
92 | $tags[$current_tag] .= trim(join(' ', $words));
93 | }
94 | }
95 |
96 | foreach($tags as $name => $val) {
97 | if( is_array($val) ) {
98 | foreach($val as $subName=>$subVal) {
99 | if( is_string($subVal) )
100 | $tags[$name][$subName] = trim($subVal);
101 | }
102 | } else {
103 | $tags[$name] = trim($val);
104 | }
105 | }
106 |
107 | return $tags;
108 | }
109 |
110 | /**
111 | * @param \ReflectionClass|\ReflectionMethod $reflection
112 | * @return string
113 | */
114 | private function getNameSpace($reflection)
115 | {
116 | if ($reflection instanceof \ReflectionClass) {
117 | return $reflection->getNamespaceName();
118 | } else {
119 | return $reflection->getDeclaringClass()->getNamespaceName();
120 | }
121 | }
122 |
123 | /**
124 | * @param $line
125 | * @return array
126 | */
127 | private function getWordsFromLine($line)
128 | {
129 | $words = [];
130 | foreach(explode(' ', trim($line)) as $w) {
131 | if( !empty($w) ) {
132 | $words[] = $w;
133 | }
134 | }
135 | return $words;
136 | }
137 |
138 | /**
139 | * @param $words
140 | * @param $currentNameSpace
141 | * @return array|bool
142 | */
143 | private function figureOutParamDeclaration($words, $currentNameSpace)
144 | {
145 | $description = '';
146 | $type = '';
147 | $name = '';
148 |
149 | if (isset($words[1]) && strpos($words[1], '$') === 0) {
150 | $name = $words[1];
151 | $type = 'mixed';
152 | array_splice($words, 0, 2);
153 | } elseif (isset($words[2])) {
154 | $name = $words[2];
155 | $type = $words[1];
156 | array_splice($words, 0, 3);
157 | }
158 |
159 | if (!empty($name)) {
160 | $name = current(explode('=', $name));
161 | if( count($words) > 1 ) {
162 | $description = join(' ', $words);
163 | }
164 |
165 | $type = Utils::sanitizeDeclaration($type, $currentNameSpace);
166 |
167 | $data = [
168 | 'description' => $description,
169 | 'name' => $name,
170 | 'type' => $type,
171 | 'default' => false
172 | ];
173 |
174 | return [$name, $data];
175 | }
176 |
177 | return false;
178 | }
179 |
180 | /**
181 | * @param $words
182 | * @return array|false
183 | */
184 | private function figureOutSeeDeclaration($words)
185 | {
186 | array_shift($words);
187 |
188 | if (!$words) {
189 | $see = false;
190 | } elseif (preg_match('#^http://|^https://#', $words[0])) {
191 | $see = count($words) > 1
192 | ? '[' . implode(' ', array_slice($words, 1)) . '](' . $words[0] . ')'
193 | : '<' . $words[0] . '>';
194 | } else {
195 | $see = implode(' ', $words);
196 | }
197 |
198 | return $see;
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/FunctionEntity.php:
--------------------------------------------------------------------------------
1 | isStatic;
58 | } else {
59 | return $this->isStatic = (bool)$toggle;
60 | }
61 | }
62 |
63 | /**
64 | * @param bool $toggle
65 | */
66 | public function isAbstract($toggle=null)
67 | {
68 | if ( $toggle === null ) {
69 | return $this->abstract;
70 | } else {
71 | return $this->abstract = (bool)$toggle;
72 | }
73 | }
74 |
75 | /**
76 | * @param bool $toggle
77 | */
78 | public function isReturningNativeClass($toggle=null)
79 | {
80 | if ( $toggle === null ) {
81 | return $this->isReturningNativeClass;
82 | } else {
83 | return $this->isReturningNativeClass = (bool)$toggle;
84 | }
85 | }
86 |
87 | /**
88 | * @return bool
89 | */
90 | public function hasParams()
91 | {
92 | return !empty($this->params);
93 | }
94 |
95 | /**
96 | * @param \PHPDocsMD\ParamEntity[] $params
97 | */
98 | public function setParams(array $params)
99 | {
100 | $this->params = $params;
101 | }
102 |
103 | /**
104 | * @return \PHPDocsMD\ParamEntity[]
105 | */
106 | public function getParams()
107 | {
108 | return $this->params;
109 | }
110 |
111 | /**
112 | * @param string $returnType
113 | */
114 | public function setReturnType($returnType)
115 | {
116 | $this->returnType = $returnType;
117 | }
118 |
119 | /**
120 | * @return string
121 | */
122 | public function getReturnType()
123 | {
124 | return $this->returnType;
125 | }
126 |
127 | /**
128 | * @param string $visibility
129 | */
130 | public function setVisibility($visibility)
131 | {
132 | $this->visibility = $visibility;
133 | }
134 |
135 | /**
136 | * @return string
137 | */
138 | public function getVisibility()
139 | {
140 | return $this->visibility;
141 | }
142 |
143 | /**
144 | * @param string $class
145 | */
146 | public function setClass($class)
147 | {
148 | $this->class = $class;
149 | }
150 |
151 | /**
152 | * @return string
153 | */
154 | public function getClass()
155 | {
156 | return $this->class;
157 | }
158 |
159 | /**
160 | * @param array $see
161 | */
162 | public function setSee(array $see)
163 | {
164 | $this->see = $see;
165 | }
166 |
167 | /**
168 | * @return array
169 | */
170 | public function getSee()
171 | {
172 | return $this->see;
173 | }
174 | }
175 |
176 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/FunctionFinder.php:
--------------------------------------------------------------------------------
1 | find($methodName, $className);
24 | if (false !== $function) {
25 | return $function;
26 | }
27 | }
28 | return false;
29 | }
30 |
31 | /**
32 | * @param string $methodName
33 | * @param string $className
34 | * @return bool|FunctionEntity
35 | */
36 | public function find($methodName, $className)
37 | {
38 | if ($className) {
39 | $classEntity = $this->loadClassEntity($className);
40 | $functions = $classEntity->getFunctions();
41 | foreach($functions as $function) {
42 | if($function->getName() == $methodName) {
43 | return $function;
44 | }
45 | }
46 | if($classEntity->getExtends()) {
47 | return $this->find($methodName, $classEntity->getExtends());
48 | }
49 | }
50 | return false;
51 | }
52 |
53 | /**
54 | * @param $className
55 | * @return ClassEntity
56 | */
57 | private function loadClassEntity($className)
58 | {
59 | if (empty($this->cache[$className])) {
60 | $reflector = new Reflector($className, $this);
61 | $this->cache[$className] = $reflector->getClassEntity();
62 | }
63 |
64 | return $this->cache[$className];
65 | }
66 | }
--------------------------------------------------------------------------------
/src/PHPDocsMD/MDTableGenerator.php:
--------------------------------------------------------------------------------
1 |
11 | * openTable();
14 | * foreach($classEntity->getFunctions() as $func) {
15 | * $generator->addFunc( $func );
16 | * }
17 | * echo $generator->getTable();
18 | *
19 | *
20 | * @package PHPDocsMD
21 | */
22 | class MDTableGenerator implements TableGenerator
23 | {
24 |
25 | /**
26 | * @var string
27 | */
28 | private $fullClassName = '';
29 |
30 | /**
31 | * @var string
32 | */
33 | private $markdown = '';
34 |
35 | /**
36 | * @var array
37 | */
38 | private $examples = [];
39 |
40 | /**
41 | * @var bool
42 | */
43 | private $appendExamples = true;
44 |
45 | /**
46 | * @var bool
47 | */
48 | private $declareAbstraction = true;
49 |
50 | /**
51 | * @param $example
52 | * @return mixed
53 | */
54 | private static function stripCodeTags($example)
55 | {
56 | if (strpos($example, '', $example), -2);
58 | $example = current($parts);
59 | $parts = array_slice(explode('', $example), 1);
60 | $example = current($parts);
61 | }
62 | return $example;
63 | }
64 |
65 | /**
66 | * All example comments found while generating the table will be
67 | * appended to the end of the table. Set $toggle to false to
68 | * prevent this behaviour
69 | *
70 | * @param bool $toggle
71 | */
72 | function appendExamplesToEndOfTable($toggle)
73 | {
74 | $this->appendExamples = (bool)$toggle;
75 | }
76 |
77 | /**
78 | * Begin generating a new markdown-formatted table
79 | */
80 | function openTable()
81 | {
82 | $this->examples = [];
83 | $this->markdown = ''; // Clear table
84 | $this->declareAbstraction = true;
85 | $this->add('| Visibility | Function |');
86 | $this->add('|:-----------|:---------|');
87 | }
88 |
89 | /**
90 | * Toggle whether or not methods being abstract (or part of an interface)
91 | * should be declared as abstract in the table
92 | * @param bool $toggle
93 | */
94 | function doDeclareAbstraction($toggle) {
95 | $this->declareAbstraction = (bool)$toggle;
96 | }
97 |
98 | /**
99 | * Generates a markdown formatted table row with information about given function. Then adds the
100 | * row to the table and returns the markdown formatted string.
101 | *
102 | * @param FunctionEntity $func
103 | * @param bool $see
104 | * @return string
105 | */
106 | function addFunc(FunctionEntity $func, $includeSee=false)
107 | {
108 | $this->fullClassName = $func->getClass();
109 |
110 | $str = '';
111 |
112 | if( $this->declareAbstraction && $func->isAbstract() )
113 | $str .= 'abstract ';
114 |
115 | $str .= $func->getName().'(';
116 |
117 | if( $func->hasParams() ) {
118 | $params = [];
119 | foreach($func->getParams() as $param) {
120 | $paramStr = ''.$param->getType().' '.$param->getName();
121 | if( $param->getDefault() ) {
122 | $paramStr .= '='.$param->getDefault();
123 | }
124 | $paramStr .= '';
125 | $params[] = $paramStr;
126 | }
127 | $str .= ''.implode(', ', $params) .')';
128 | } else {
129 | $str .= ')';
130 | }
131 |
132 | $str .= ' : '.$func->getReturnType().'';
133 |
134 | if( $func->isDeprecated() ) {
135 | $str = ''.$str.'';
136 | $str .= '
DEPRECATED - '.$func->getDeprecationMessage().'';
137 | } elseif( $func->getDescription() ) {
138 | $str .= '
'.$func->getDescription().'';
139 | }
140 | if ($func->getSee() && $includeSee) {
141 | $str .= '
See: ' .
142 | implode(', ', $func->getSee()) . '';
143 | }
144 |
145 | $str = str_replace(['', ' '], ['',''], trim($str));
146 |
147 | if( $func->getExample() )
148 | $this->examples[$func->getName()] = $func->getExample();
149 |
150 | $firstCol = $func->getVisibility() . ($func->isStatic() ? ' static':'');
151 | $markDown = '| '.$firstCol.' | '.$str.' |';
152 |
153 | $this->add($markDown);
154 | return $markDown;
155 | }
156 |
157 | /**
158 | * @return string
159 | */
160 | function getTable()
161 | {
162 | $tbl = trim($this->markdown);
163 | if( $this->appendExamples && !empty($this->examples) ) {
164 | $className = Utils::getClassBaseName($this->fullClassName);
165 | foreach ($this->examples as $funcName => $example) {
166 | $tbl .= sprintf("\n###### Examples of %s::%s()\n%s", $className, $funcName, self::formatExampleComment($example));
167 | }
168 | }
169 | return $tbl;
170 | }
171 |
172 | /**
173 | * Create a markdown-formatted code view out of an example comment
174 | * @param string $example
175 | * @return string
176 | */
177 | public static function formatExampleComment($example)
178 | {
179 | // Remove possible code tag
180 | $example = self::stripCodeTags($example);
181 |
182 | if( preg_match('/(\n )/', $example) ) {
183 | $example = preg_replace('/(\n )/', "\n", $example);
184 | }
185 | elseif( preg_match('/(\n )/', $example) ) {
186 | $example = preg_replace('/(\n )/', "\n", $example);
187 | } else {
188 | $example = preg_replace('/(\n )/', "\n", $example);
189 | }
190 | $type = '';
191 |
192 | // A very naive analysis of the programming language used in the comment
193 | if( strpos($example, 'markdown .= $str .PHP_EOL;
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/ParamEntity.php:
--------------------------------------------------------------------------------
1 | default = $default;
27 | }
28 |
29 | /**
30 | * @return boolean
31 | */
32 | public function getDefault()
33 | {
34 | return $this->default;
35 | }
36 |
37 | /**
38 | * @param string $type
39 | */
40 | public function setType($type)
41 | {
42 | $this->type = $type;
43 | }
44 |
45 | /**
46 | * @return string
47 | */
48 | public function getType()
49 | {
50 | return $this->type;
51 | }
52 |
53 | /**
54 | * @return string|null
55 | */
56 | public function getNativeClassType()
57 | {
58 | foreach(explode('/', $this->type) as $typeDeclaration) {
59 | if (Utils::isNativeClassReference($typeDeclaration)) {
60 | return $typeDeclaration;
61 | }
62 | }
63 | return null;
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/Reflector.php:
--------------------------------------------------------------------------------
1 | className = $className;
61 | $this->functionFinder = $this->loadIfNull($functionFinder, FunctionFinder::class);
62 | $this->docInfoExtractor = $this->loadIfNull($docInfoExtractor, DocInfoExtractor::class);
63 | $this->useInspector = $this->loadIfNull($useInspector, UseInspector::class);
64 | $this->classEntityFactory = $this->loadIfNull(
65 | $classEntityFactory,
66 | ClassEntityFactory::class,
67 | $this->docInfoExtractor
68 | );
69 | }
70 |
71 | private function loadIfNull($obj, $className, $in=null)
72 | {
73 | return is_object($obj) ? $obj : new $className($in);
74 | }
75 |
76 | /**
77 | * @return \PHPDocsMD\ClassEntity
78 | */
79 | function getClassEntity() {
80 | $classReflection = new \ReflectionClass($this->className);
81 | $classEntity = $this->classEntityFactory->create($classReflection);
82 |
83 | $classEntity->setFunctions($this->getClassFunctions($classEntity, $classReflection));
84 |
85 | return $classEntity;
86 | }
87 |
88 | /**
89 | * @param ClassEntity $classEntity
90 | * @param \ReflectionClass $reflectionClass
91 | * @return FunctionEntity[]
92 | */
93 | private function getClassFunctions(ClassEntity $classEntity, \ReflectionClass $reflectionClass)
94 | {
95 | $classUseStatements = $this->useInspector->getUseStatements($reflectionClass);
96 | $publicFunctions = [];
97 | $protectedFunctions = [];
98 | $methodReflections = [];
99 |
100 | if (count($this->visibilityFilter) === 0) {
101 | $methodReflections = $reflectionClass->getMethods();
102 | } else {
103 | foreach ($this->visibilityFilter as $filter) {
104 | $methodReflections[] = $reflectionClass->getMethods($this->translateVisibilityFilter($filter));
105 | }
106 | $methodReflections = call_user_func_array('array_merge', $methodReflections);
107 | }
108 |
109 | if ($this->methodRegex !== '') {
110 | $methodReflections = array_filter($methodReflections, function (ReflectionMethod $reflectionMethod) {
111 | return preg_match($this->methodRegex, $reflectionMethod->name);
112 | });
113 | }
114 |
115 | foreach($methodReflections as $methodReflection) {
116 |
117 | $func = $this->createFunctionEntity(
118 | $methodReflection,
119 | $classEntity,
120 | $classUseStatements
121 | );
122 |
123 |
124 | if( $func ) {
125 | if( $func->getVisibility() == 'public' ) {
126 | $publicFunctions[$func->getName()] = $func;
127 | } else {
128 | $protectedFunctions[$func->getName()] = $func;
129 | }
130 | }
131 | }
132 |
133 | ksort($publicFunctions);
134 | ksort($protectedFunctions);
135 |
136 | return array_values(array_merge($publicFunctions, $protectedFunctions));
137 | }
138 |
139 | /**
140 | * @param ReflectionMethod $method
141 | * @param ClassEntity $class
142 | * @param array $useStatements
143 | * @return bool|FunctionEntity
144 | */
145 | protected function createFunctionEntity(ReflectionMethod $method, ClassEntity $class, $useStatements)
146 | {
147 | $func = new FunctionEntity();
148 | $docInfo = $this->docInfoExtractor->extractInfo($method);
149 | $this->docInfoExtractor->applyInfoToEntity($method, $docInfo, $func);
150 |
151 | if ($docInfo->shouldInheritDoc()) {
152 | return $this->findInheritedFunctionDeclaration($func, $class);
153 | }
154 |
155 | if ($this->shouldIgnoreFunction($docInfo, $method, $class)) {
156 | return false;
157 | }
158 |
159 | $returnType = $this->getReturnType($docInfo, $method, $func, $useStatements);
160 | $func->setReturnType($returnType);
161 | $func->setParams($this->getParams($method, $docInfo));
162 | $func->isStatic($method->isStatic());
163 | $func->setVisibility($method->isPublic() ? 'public' : 'protected');
164 | $func->isAbstract($method->isAbstract());
165 | $func->setClass($class->getName());
166 | $func->isReturningNativeClass(Utils::isNativeClassReference($returnType));
167 |
168 | return $func;
169 | }
170 |
171 | /**
172 | * @param DocInfo $docInfo
173 | * @param ReflectionMethod $method
174 | * @param FunctionEntity $func
175 | * @param array $useStatements
176 | * @return string
177 | */
178 | private function getReturnType(
179 | DocInfo $docInfo,
180 | ReflectionMethod $method,
181 | FunctionEntity $func,
182 | array $useStatements
183 | ) {
184 | $returnType = $docInfo->getReturnType();
185 | if (empty($returnType)) {
186 | $returnType = $this->guessReturnTypeFromFuncName($func->getName());
187 | } elseif(Utils::isClassReference($returnType) && !self::classExists($returnType)) {
188 | $isReferenceToArrayOfObjects = substr($returnType, -2) == '[]' ? '[]':'';
189 | if ($isReferenceToArrayOfObjects) {
190 | $returnType = substr($returnType, 0, strlen($returnType)-2);
191 | }
192 | $className = $this->stripAwayNamespace($returnType);
193 | foreach ($useStatements as $usedClass) {
194 | if ($this->stripAwayNamespace($usedClass) == $className) {
195 | $returnType = $usedClass;
196 | break;
197 | }
198 | }
199 | if ($isReferenceToArrayOfObjects) {
200 | $returnType .= '[]';
201 | }
202 | }
203 |
204 | return Utils::sanitizeDeclaration(
205 | $returnType,
206 | $method->getDeclaringClass()->getNamespaceName()
207 | );
208 | }
209 |
210 | /**
211 | * @param string $classRef
212 | * @return bool
213 | */
214 | private function classExists($classRef)
215 | {
216 | return class_exists(trim($classRef, '[]'));
217 | }
218 |
219 | /**
220 | * @param string $className
221 | * @return string
222 | */
223 | private function stripAwayNamespace($className)
224 | {
225 | return trim(substr($className, strrpos($className, '\\')), '\\');
226 | }
227 |
228 | /**
229 | * @param DocInfo $info
230 | * @param ReflectionMethod $method
231 | * @param ClassEntity $class
232 | * @return bool
233 | */
234 | protected function shouldIgnoreFunction($info, ReflectionMethod $method, $class)
235 | {
236 | return $info->shouldBeIgnored() ||
237 | $method->isPrivate() ||
238 | !$class->isSame($method->getDeclaringClass()->getName());
239 | }
240 |
241 | /**
242 | * @todo Turn this into a class "FunctionEntityFactory"
243 | * @param \ReflectionParameter $reflection
244 | * @param array $docs
245 | * @return FunctionEntity
246 | */
247 | private function createParameterEntity(\ReflectionParameter $reflection, $docs)
248 | {
249 | // need to use slash instead of pipe or md-generation will get it wrong
250 | $def = false;
251 | $type = 'mixed';
252 | $declaredType = self::getParamType($reflection);
253 | if( !isset($docs['type']) )
254 | $docs['type'] = '';
255 |
256 | if( $declaredType && !($declaredType=='array' && substr($docs['type'], -2) == '[]') && $declaredType != $docs['type']) {
257 | if( $declaredType && $docs['type'] ) {
258 | $posClassA = Utils::getClassBaseName($docs['type']);
259 | $posClassB = Utils::getClassBaseName($declaredType);
260 | if( $posClassA == $posClassB ) {
261 | $docs['type'] = $declaredType;
262 | } else {
263 | $docs['type'] = empty($docs['type']) ? $declaredType : $docs['type'].'/'.$declaredType;
264 | }
265 | } else {
266 | $docs['type'] = empty($docs['type']) ? $declaredType : $docs['type'].'/'.$declaredType;
267 | }
268 | }
269 |
270 | try {
271 | $def = $reflection->getDefaultValue();
272 | $type = $this->getTypeFromVal($def);
273 | if( is_string($def) ) {
274 | $def = "`'$def'`";
275 | } elseif( is_bool($def) ) {
276 | $def = $def ? 'true':'false';
277 | } elseif( is_null($def) ) {
278 | $def = 'null';
279 | } elseif( is_array($def) ) {
280 | $def = 'array()';
281 | }
282 | } catch(\Exception $e) {}
283 |
284 | $varName = '$'.$reflection->getName();
285 |
286 | if( !empty($docs) ) {
287 | $docs['default'] = $def;
288 | if( $type == 'mixed' && $def == 'null' && strpos($docs['type'], '\\') === 0 ) {
289 | $type = false;
290 | }
291 | if( $type && $def && !empty($docs['type']) && $docs['type'] != $type && strpos($docs['type'], '|') === false) {
292 | if( substr($docs['type'], strpos($docs['type'], '\\')) == substr($declaredType, strpos($declaredType, '\\')) ) {
293 | $docs['type'] = $declaredType;
294 | } else {
295 | $docs['type'] = ($type == 'mixed' ? '':$type.'/').$docs['type'];
296 | }
297 | } elseif( $type && empty($docs['type']) ) {
298 | $docs['type'] = $type;
299 | }
300 | } else {
301 | $docs = [
302 | 'descriptions'=>'',
303 | 'name' => $varName,
304 | 'default' => $def,
305 | 'type' => $type
306 | ];
307 | }
308 |
309 | $param = new ParamEntity();
310 | $param->setDescription(isset($docs['description']) ? $docs['description']:'');
311 | $param->setName($varName);
312 | $param->setDefault($docs['default']);
313 | $param->setType(empty($docs['type']) ? 'mixed':str_replace(['|', '\\\\'], ['/', '\\'], $docs['type']));
314 | return $param;
315 | }
316 |
317 | /**
318 | * Tries to find out if the type of the given parameter. Will
319 | * return empty string if not possible.
320 | *
321 | * @example
322 | *
323 | * getMethods() as $method ) {
326 | * foreach($method->getParameters() as $param) {
327 | * $name = $param->getName();
328 | * $type = Reflector::getParamType($param);
329 | * printf("%s = %s\n", $name, $type);
330 | * }
331 | * }
332 | *
333 | *
334 | * @param \ReflectionParameter $refParam
335 | * @return string
336 | */
337 | static function getParamType(\ReflectionParameter $refParam)
338 | {
339 | $export = str_replace(' or NULL', '', (string)$refParam);
340 |
341 | $type = preg_replace('/.*?([\w\\\]+)\s+\$'.current(explode('=', $refParam->name)).'.*/', '\\1', $export);
342 | if( strpos($type, 'Parameter ') !== false ) {
343 | return '';
344 | }
345 |
346 | if( $type != 'array' && strpos($type, '\\') !== 0 ) {
347 | $type = '\\'.$type;
348 | }
349 |
350 | return $type;
351 | }
352 |
353 | /**
354 | * @param string $name
355 | * @return string
356 | */
357 | private function guessReturnTypeFromFuncName($name)
358 | {
359 | $mixed = ['get', 'load', 'fetch', 'find', 'create'];
360 | $bool = ['is', 'can', 'has', 'have', 'should'];
361 | foreach($mixed as $prefix) {
362 | if( strpos($name, $prefix) === 0 )
363 | return 'mixed';
364 | }
365 | foreach($bool as $prefix) {
366 | if( strpos($name, $prefix) === 0 )
367 | return 'bool';
368 | }
369 | return 'void';
370 | }
371 |
372 | /**
373 | * @param string $def
374 | * @return string
375 | */
376 | private function getTypeFromVal($def)
377 | {
378 | if( is_string($def) ) {
379 | return 'string';
380 | } elseif( is_bool($def) ) {
381 | return 'bool';
382 | } elseif( is_array($def) ) {
383 | return 'array';
384 | } else {
385 | return 'mixed';
386 | }
387 | }
388 |
389 | /**
390 | * @param FunctionEntity $func
391 | * @param ClassEntity $class
392 | * @return FunctionEntity
393 | */
394 | private function findInheritedFunctionDeclaration(FunctionEntity $func, ClassEntity $class)
395 | {
396 | $funcName = $func->getName();
397 | $inheritedFuncDeclaration = $this->functionFinder->find(
398 | $funcName,
399 | $class->getExtends()
400 | );
401 | if (!$inheritedFuncDeclaration) {
402 | $inheritedFuncDeclaration = $this->functionFinder->findInClasses(
403 | $funcName,
404 | $class->getInterfaces()
405 | );
406 | if (!$inheritedFuncDeclaration) {
407 | throw new \RuntimeException(
408 | 'Function '.$funcName.' tries to inherit docs but no parent method is found'
409 | );
410 | }
411 | }
412 | if (!$func->isAbstract() && !$class->isAbstract() && $inheritedFuncDeclaration->isAbstract()) {
413 | $inheritedFuncDeclaration->isAbstract(false);
414 | }
415 | return $inheritedFuncDeclaration;
416 | }
417 |
418 | /**
419 | * @param ReflectionMethod $method
420 | * @param DocInfo $docInfo
421 | * @return array
422 | */
423 | private function getParams(ReflectionMethod $method, $docInfo)
424 | {
425 | $params = [];
426 | foreach ($method->getParameters() as $param) {
427 | $paramName = '$' . $param->getName();
428 | $params[$param->getName()] = $this->createParameterEntity(
429 | $param,
430 | $docInfo->getParameterInfo($paramName)
431 | );
432 | }
433 | return array_values($params);
434 | }
435 |
436 | private function translateVisibilityFilter($filter){
437 | $map = [
438 | 'public' => ReflectionMethod::IS_PUBLIC,
439 | 'protected' => ReflectionMethod::IS_PROTECTED,
440 | 'abstract' => ReflectionMethod::IS_ABSTRACT,
441 | 'final' => ReflectionMethod::IS_FINAL,
442 | ];
443 |
444 | return isset($map[$filter]) ? $map[$filter] : null;
445 | }
446 |
447 | public function setVisibilityFilter( array $visibilityFilter )
448 | {
449 | $this->visibilityFilter = $visibilityFilter;
450 | }
451 |
452 | public function setMethodRegex($methodRegex)
453 | {
454 | $this->methodRegex = $methodRegex;
455 | }
456 | }
457 |
--------------------------------------------------------------------------------
/src/PHPDocsMD/ReflectorInterface.php:
--------------------------------------------------------------------------------
1 | getUseStatementsInString(file_get_contents($filePath));
34 | }
35 |
36 | /**
37 | * @param \ReflectionClass $reflectionClass
38 | * @return array
39 | */
40 | public function getUseStatements(\ReflectionClass $reflectionClass)
41 | {
42 | $classUseStatements = [];
43 | $classFile = $reflectionClass->getFileName();
44 | if ($classFile) {
45 | $classUseStatements = $this->getUseStatementsInFile($classFile);
46 | }
47 | return $classUseStatements;
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/src/PHPDocsMD/Utils.php:
--------------------------------------------------------------------------------
1 | $p) {
39 | if (self::shouldPrefixWithNamespace($p)) {
40 | $p = self::sanitizeClassName('\\' . trim($currentNameSpace, '\\') . '\\' . $p);
41 | } elseif (self::isClassReference($p)) {
42 | $p = self::sanitizeClassName($p);
43 | }
44 | $parts[$i] = $p;
45 | }
46 | return implode('/', $parts);
47 | }
48 |
49 | /**
50 | * @param string $typeDeclaration
51 | * @return bool
52 | */
53 | private static function shouldPrefixWithNameSpace($typeDeclaration)
54 | {
55 | return strpos($typeDeclaration, '\\') !== 0 && self::isClassReference($typeDeclaration);
56 | }
57 |
58 | /**
59 | * @param string $typeDeclaration
60 | * @return bool
61 | */
62 | public static function isClassReference($typeDeclaration)
63 | {
64 | $natives = [
65 | 'mixed',
66 | 'string',
67 | 'int',
68 | 'float',
69 | 'integer',
70 | 'number',
71 | 'bool',
72 | 'boolean',
73 | 'object',
74 | 'false',
75 | 'true',
76 | 'null',
77 | 'array',
78 | 'void',
79 | 'callable'
80 | ];
81 | $sanitizedTypeDeclaration = rtrim(trim(strtolower($typeDeclaration)), '[]');
82 |
83 | return !in_array($sanitizedTypeDeclaration, $natives) &&
84 | strpos($typeDeclaration, ' ') === false;
85 | }
86 |
87 | public static function isNativeClassReference($typeDeclaration)
88 | {
89 | $sanitizedType = str_replace('[]', '', $typeDeclaration);
90 | if (Utils::isClassReference($typeDeclaration) && class_exists($sanitizedType, false)) {
91 | $reflectionClass = new \ReflectionClass($sanitizedType);
92 | return !$reflectionClass->getFileName();
93 | }
94 | return false;
95 | }
96 | }
--------------------------------------------------------------------------------
/test/ExampleClass.php:
--------------------------------------------------------------------------------
1 |
40 | *
44 | *
45 | * @param int $arg
46 | * @param array $arr
47 | * @param int $bool
48 | */
49 | function funcB($arg, array $arr, $bool=10) {
50 |
51 | }
52 |
53 | function funcD($arg, $arr=array(), ExampleInterface $depr=null, \stdClass $class = null) {
54 |
55 | }
56 |
57 | function getFunc() {}
58 | function hasFunc() {}
59 | abstract function isFunc();
60 |
61 | /**
62 | * @ignore
63 | */
64 | function someFunc() {
65 |
66 | }
67 |
68 | private function privFunc() {
69 |
70 | }
71 |
72 | }
73 |
74 | /**
75 | * @deprecated This one is deprecated
76 | *
77 | * Lorem te ipsum
78 | *
79 | * @package Acme
80 | */
81 | class ExampleClassDepr {
82 |
83 | }
84 |
85 | /**
86 | * Interface ExampleInterface
87 | * @package Acme
88 | * @ignore
89 | */
90 | interface ExampleInterface {
91 |
92 | /**
93 | * @param string $arg
94 | * @return \stdClass
95 | */
96 | public function func($arg='a');
97 |
98 | }
99 |
100 | class SomeClass {
101 |
102 | /**
103 | * @return int
104 | */
105 | public function aMethod() {}
106 |
107 | }
108 |
109 | class ClassImplementingInterface extends SomeClass implements ExampleInterface {
110 | /**
111 | * @inheritdoc
112 | */
113 | public function func($arg='a') {}
114 |
115 | /**
116 | * @inheritDoc
117 | */
118 | public function aMethod() {}
119 |
120 | /**
121 | * @return \FilesystemIterator
122 | */
123 | public function methodReturnNativeClass() {}
124 |
125 | /**
126 | * @return \FilesystemIterator[]
127 | */
128 | public function methodReturningArrayNativeClass() {}
129 | }
130 |
131 |
132 |
133 | class ClassWithStaticFunc {
134 |
135 | /**
136 | * @return float
137 | */
138 | static function somStaticFunc() {
139 |
140 | }
141 |
142 | }
143 |
144 | use PHPDocsMD\Console\CLI;
145 |
146 | interface InterfaceReferringToImportedClass {
147 |
148 | /**
149 | * @return CLI
150 | */
151 | function theFunc();
152 |
153 | /**
154 | * @return CLI[]
155 | */
156 | function funcReturningArr();
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/test/MDTableGeneratorTest.php:
--------------------------------------------------------------------------------
1 | openTable();
12 |
13 | $deprecated = new \PHPDocsMD\FunctionEntity();
14 | $deprecated->isDeprecated(true);
15 | $deprecated->setDeprecationMessage('Is deprecated');
16 | $deprecated->setName('myFunc');
17 | $deprecated->setReturnType('mixed');
18 |
19 | $this->assertTrue($deprecated->isDeprecated());
20 |
21 | $tbl->addFunc($deprecated);
22 |
23 | $tblMarkdown = $tbl->getTable();
24 | $expect = '| Visibility | Function |'.PHP_EOL.
25 | '|:-----------|:---------|'.PHP_EOL.
26 | '| public | myFunc() : mixed
DEPRECATED - Is deprecated |';
27 |
28 | $this->assertEquals($expect, $tblMarkdown);
29 | }
30 |
31 | function testFunc()
32 | {
33 | $tbl = new \PHPDocsMD\MDTableGenerator();
34 | $tbl->openTable();
35 |
36 | $func = new \PHPDocsMD\FunctionEntity();
37 | $func->setName('myFunc');
38 | $tbl->addFunc($func);
39 |
40 | $tblMarkdown = $tbl->getTable();
41 | $expect = '| Visibility | Function |'.PHP_EOL.
42 | '|:-----------|:---------|'.PHP_EOL.
43 | '| public | myFunc() : void |';
44 |
45 | $this->assertEquals($expect, $tblMarkdown);
46 | }
47 |
48 | function testFuncWithAllFeatures()
49 | {
50 | $tbl = new \PHPDocsMD\MDTableGenerator();
51 | $tbl->openTable();
52 |
53 | $func = new \PHPDocsMD\FunctionEntity();
54 |
55 | $this->assertFalse($func->isStatic());
56 | $this->assertFalse($func->hasParams());
57 | $this->assertFalse($func->isDeprecated());
58 | $this->assertFalse($func->isAbstract());
59 | $this->assertEquals('public', $func->getVisibility());
60 |
61 | $func->isStatic(true);
62 | $func->setVisibility('protected');
63 | $func->setName('someFunc');
64 | $func->setDescription('desc...');
65 | $func->setReturnType('\\stdClass');
66 |
67 | $params = array();
68 |
69 | $paramA = new \PHPDocsMD\ParamEntity();
70 | $paramA->setName('$var');
71 | $paramA->setType('mixed');
72 | $paramA->setDefault('null');
73 | $params[] = $paramA;
74 |
75 | $paramB = new \PHPDocsMD\ParamEntity();
76 | $paramB->setName('$other');
77 | $paramB->setType('string');
78 | $paramB->setDefault("'test'");
79 | $params[] = $paramB;
80 |
81 | $func->setParams($params);
82 |
83 | $tbl->addFunc($func);
84 |
85 | $this->assertTrue($func->isStatic());
86 | $this->assertTrue($func->hasParams());
87 | $this->assertEquals('protected', $func->getVisibility());
88 |
89 | $tblMarkdown = $tbl->getTable();
90 | $expect = '| Visibility | Function |'.PHP_EOL.
91 | '|:-----------|:---------|'.PHP_EOL.
92 | '| protected static | someFunc(mixed $var=null, string $other=\'test\') : \\stdClass
desc... |';
93 |
94 | $this->assertEquals($expect, $tblMarkdown);
95 | }
96 |
97 | function testToggleDeclaringAbstraction()
98 | {
99 | $tbl = new \PHPDocsMD\MDTableGenerator();
100 | $tbl->openTable();
101 |
102 | $func = new \PHPDocsMD\FunctionEntity();
103 | $func->isAbstract(true);
104 | $func->setName('someFunc');
105 |
106 | $tbl->addFunc($func);
107 | $tblMarkdown = $tbl->getTable();
108 | $expect = '| Visibility | Function |'.PHP_EOL.
109 | '|:-----------|:---------|'.PHP_EOL.
110 | '| public | abstract someFunc() : void |';
111 |
112 | $this->assertEquals($expect, $tblMarkdown);
113 |
114 | $tbl->openTable();
115 | $tbl->doDeclareAbstraction(false);
116 | $tbl->addFunc($func);
117 |
118 | $tblMarkdown = $tbl->getTable();
119 | $expect = '| Visibility | Function |'.PHP_EOL.
120 | '|:-----------|:---------|'.PHP_EOL.
121 | '| public | someFunc() : void |';
122 |
123 | $this->assertEquals($expect, $tblMarkdown);
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/test/ReflectorTest.php:
--------------------------------------------------------------------------------
1 | reflector = new Reflector('Acme\\ExampleClass');
24 | $this->class = $this->reflector->getClassEntity();
25 | }
26 |
27 | function testClass()
28 | {
29 | $this->assertEquals('\\Acme\\ExampleClass', $this->class->getName());
30 | $this->assertEquals('This is a description of this class', $this->class->getDescription());
31 | $this->assertEquals('Class: \\Acme\\ExampleClass (abstract)', $this->class->generateTitle());
32 | $this->assertEquals('class-acmeexampleclass-abstract', $this->class->generateAnchor());
33 | $this->assertFalse($this->class->isDeprecated());
34 | $this->assertFalse($this->class->hasIgnoreTag());
35 |
36 | $refl = new Reflector('Acme\\ExampleClassDepr');
37 | $class = $refl->getClassEntity();
38 | $this->assertTrue($class->isDeprecated());
39 | $this->assertEquals('This one is deprecated Lorem te ipsum', $class->getDeprecationMessage());
40 | $this->assertFalse($class->hasIgnoreTag());
41 |
42 | $refl = new Reflector('Acme\\ExampleInterface');
43 | $class = $refl->getClassEntity();
44 | $this->assertTrue($class->isInterface());
45 | $this->assertTrue($class->hasIgnoreTag());
46 | }
47 |
48 | function testFunctions()
49 | {
50 |
51 | $functions = $this->class->getFunctions();
52 |
53 | $this->assertNotEmpty($functions);
54 |
55 | $this->assertEquals('Description of a*a', $functions[0]->getDescription());
56 | $this->assertEquals(false, $functions[0]->isDeprecated());
57 | $this->assertEquals('funcA', $functions[0]->getName());
58 | $this->assertEquals('void', $functions[0]->getReturnType());
59 | $this->assertEquals('public', $functions[0]->getVisibility());
60 |
61 | $this->assertEquals('Description of b', $functions[1]->getDescription());
62 | $this->assertEquals(false, $functions[1]->isDeprecated());
63 | $this->assertEquals('funcB', $functions[1]->getName());
64 | $this->assertEquals('void', $functions[1]->getReturnType());
65 | $this->assertEquals('public', $functions[1]->getVisibility());
66 |
67 |
68 | $this->assertEquals('', $functions[2]->getDescription());
69 | $this->assertEquals('funcD', $functions[2]->getName());
70 | $this->assertEquals('void', $functions[2]->getReturnType());
71 | $this->assertEquals('public', $functions[2]->getVisibility());
72 | $this->assertEquals(false, $functions[2]->isDeprecated());
73 |
74 | // These function does not declare return type but the return
75 | // type should be guessable
76 | $this->assertEquals('mixed', $functions[3]->getReturnType());
77 | $this->assertEquals('bool', $functions[4]->getReturnType());
78 | $this->assertEquals('bool', $functions[5]->getReturnType());
79 | $this->assertTrue($functions[5]->isAbstract());
80 | $this->assertTrue($this->class->isAbstract());
81 |
82 | // Protected function have been put last
83 | $this->assertEquals('Description of c', $functions[6]->getDescription());
84 | $this->assertEquals(true, $functions[6]->isDeprecated());
85 | $this->assertEquals('This one is deprecated', $functions[6]->getDeprecationMessage());
86 | $this->assertEquals('funcC', $functions[6]->getName());
87 | $this->assertEquals('\\Acme\\ExampleClass', $functions[6]->getReturnType());
88 | $this->assertEquals('protected', $functions[6]->getVisibility());
89 |
90 | $this->assertTrue( empty($functions[7]) ); // Should be skipped since tagged with @ignore */
91 | }
92 |
93 | function testStaticFunc() {
94 | $reflector = new Reflector('Acme\\ClassWithStaticFunc');
95 | $functions = $reflector->getClassEntity()->getFunctions();
96 | $this->assertNotEmpty($functions);
97 | $this->assertEquals('', $functions[0]->getDescription());
98 | $this->assertEquals(false, $functions[0]->isDeprecated());
99 | $this->assertEquals(true, $functions[0]->isStatic());
100 | $this->assertEquals('', $functions[0]->getDeprecationMessage());
101 | $this->assertEquals('somStaticFunc', $functions[0]->getName());
102 | $this->assertEquals('public', $functions[0]->getVisibility());
103 | $this->assertEquals('float', $functions[0]->getReturnType());
104 | }
105 |
106 | function testParams()
107 | {
108 | $paramA = new ReflectionParameter(array('Acme\\ExampleClass', 'funcD'), 2);
109 | $paramB = new ReflectionParameter(array('Acme\\ExampleClass', 'funcD'), 3);
110 | $paramC = new ReflectionParameter(array('Acme\\ExampleClass', 'funcD'), 0);
111 |
112 | $typeA = Reflector::getParamType($paramA);
113 | $typeB = Reflector::getParamType($paramB);
114 | $typeC = Reflector::getParamType($paramC);
115 |
116 | $this->assertEmpty($typeC);
117 | $this->assertEquals('\\stdClass', $typeB);
118 | $this->assertEquals('\\Acme\\ExampleInterface', $typeA);
119 |
120 | $functions = $this->class->getFunctions();
121 |
122 | $this->assertTrue($functions[2]->hasParams());
123 | $this->assertFalse($functions[5]->hasParams());
124 |
125 | $params = $functions[1]->getParams();
126 | $this->assertEquals('int', $params[0]->getType());
127 |
128 | $params = $functions[2]->getParams();
129 | $this->assertEquals(4, count($params));
130 | $this->assertEquals(false, $params[0]->getDefault());
131 | $this->assertEquals('$arg', $params[0]->getName());
132 | $this->assertEquals('mixed', $params[0]->getType());
133 | $this->assertEquals('array()', $params[1]->getDefault());
134 | $this->assertEquals('$arr', $params[1]->getName());
135 | $this->assertEquals('array', $params[1]->getType());
136 | $this->assertEquals('null', $params[2]->getDefault());
137 | $this->assertEquals('$depr', $params[2]->getName());
138 | $this->assertEquals('\\Acme\\ExampleInterface', $params[2]->getType());
139 | }
140 |
141 | function testInheritedDocs()
142 | {
143 | $reflector = new Reflector('Acme\\ClassImplementingInterface');
144 | $functions = $reflector->getClassEntity()->getFunctions();
145 | $this->assertEquals(4, count($functions));
146 | $this->assertEquals('aMethod', $functions[0]->getName());
147 | $this->assertEquals('int', $functions[0]->getReturnType());
148 | $this->assertFalse($functions[0]->isReturningNativeClass());
149 | $this->assertEquals('func', $functions[1]->getName());
150 | $this->assertEquals('\\stdClass', $functions[1]->getReturnType());
151 | $this->assertFalse($functions[1]->isAbstract());
152 |
153 | $this->assertTrue($functions[2]->isReturningNativeClass());
154 | $this->assertTrue($functions[3]->isReturningNativeClass());
155 | }
156 |
157 |
158 | function testReferenceToImportedClass()
159 | {
160 | $reflector = new Reflector('Acme\\InterfaceReferringToImportedClass');
161 | $functions = $reflector->getClassEntity()->getFunctions();
162 | $this->assertEquals('\\PHPDocsMD\\Console\\CLI', $functions[1]->getReturnType());
163 | $this->assertEquals('\\PHPDocsMD\\Console\\CLI[]', $functions[0]->getReturnType());
164 | }
165 |
166 | public function visibilityFiltersAndExpectedMethods()
167 | {
168 | return [
169 | 'public' => [['public'], ['funcA', 'funcB', 'funcD', 'getFunc', 'hasFunc', 'isFunc']],
170 | 'protected' => [['protected'], ['funcC']],
171 | 'public-and-protected' => [
172 | ['public', 'protected'],
173 | ['funcA', 'funcB', 'funcD', 'getFunc', 'hasFunc', 'isFunc', 'funcC'],
174 | ],
175 | 'abstract' => [['abstract'], ['isFunc']],
176 | ];
177 | }
178 |
179 | /**
180 | *@dataProvider visibilityFiltersAndExpectedMethods
181 | */
182 | public function testVisibilityBasedFiltering(array $visibilityFilter, array $expectedMethods)
183 | {
184 | $reflector = new Reflector('Acme\\ExampleClass');
185 | $reflector->setVisibilityFilter($visibilityFilter);
186 | $functions = $reflector->getClassEntity()->getFunctions();
187 | $functionNames = array_map(
188 | function (FunctionEntity $entity) {
189 | return $entity->getName();
190 | },
191 | $functions
192 | );
193 | $this->assertEquals($expectedMethods, $functionNames);
194 | }
195 |
196 | public function regexFiltersAndExpectedMethods()
197 | {
198 | return [
199 | 'has-only' => ['/^has/', ['hasFunc']],
200 | 'does-not-start-with-h' => ['/^[^h]/', ['funcA', 'funcB', 'funcD', 'getFunc', 'isFunc', 'funcC']],
201 | 'func-letter-only' => ['/^func[A-Z]/', ['funcA', 'funcB', 'funcD', 'funcC']],
202 | ];
203 | }
204 |
205 | /**
206 | *@dataProvider regexFiltersAndExpectedMethods
207 | */
208 | public function testMethodRegexFiltering($regexFilter, $expectedMethods)
209 | {
210 | $reflector = new Reflector('Acme\\ExampleClass');
211 | $reflector->setMethodRegex($regexFilter);
212 | $functions = $reflector->getClassEntity()->getFunctions();
213 | $functionNames = array_map(
214 | function (FunctionEntity $entity) {
215 | return $entity->getName();
216 | },
217 | $functions
218 | );
219 | $this->assertEquals($expectedMethods, $functionNames);
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/test/UseInspectorTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($expected, $inspector->getUseStatementsInString($code));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------