pax_global_header00006660000000000000000000000064135743121570014522gustar00rootroot0000000000000052 comment=46d317c5d3ea6c571f0c535fb5d36a7759eef9be php-zend-code-3.4.1/000077500000000000000000000000001357431215700141645ustar00rootroot00000000000000php-zend-code-3.4.1/.coveralls.yml000066400000000000000000000000751357431215700167610ustar00rootroot00000000000000coverage_clover: clover.xml json_path: coveralls-upload.json php-zend-code-3.4.1/.gitignore000066400000000000000000000002011357431215700161450ustar00rootroot00000000000000/.phpunit.result.cache /clover.xml /coveralls-upload.json /docs/html/ /phpunit.xml /vendor/ /zf-mkdoc-theme.tgz /zf-mkdoc-theme/ php-zend-code-3.4.1/.travis.yml000066400000000000000000000036011357431215700162750ustar00rootroot00000000000000language: php cache: directories: - $HOME/.composer/cache env: global: - COMPOSER_ARGS="--no-interaction" - COVERAGE_DEPS="php-coveralls/php-coveralls" - TESTS_ZEND_CODE_ANNOTATION_DOCTRINE_SUPPORT=true matrix: fast_finish: true include: - php: 7.1 env: - DEPS=lowest - php: 7.1 env: - DEPS=locked - LEGACY_DEPS="doctrine/annotations phpunit/phpunit" - CS_CHECK=true - TEST_COVERAGE=true - php: 7.1 env: - DEPS=latest - php: 7.2 env: - DEPS=lowest - php: 7.2 env: - DEPS=locked - php: 7.2 env: - DEPS=latest - php: 7.3 env: - DEPS=lowest - php: 7.3 env: - DEPS=locked - php: 7.3 env: - DEPS=latest - php: 7.4 env: - DEPS=lowest - php: 7.4 env: - DEPS=locked - php: 7.4 env: - DEPS=latest before_install: - if [[ $TEST_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi install: - travis_retry composer install $COMPOSER_ARGS --ignore-platform-reqs - if [[ $LEGACY_DEPS != '' ]]; then travis_retry composer update $COMPOSER_ARGS --with-dependencies $LEGACY_DEPS ; fi - if [[ $DEPS == 'latest' ]]; then travis_retry composer update $COMPOSER_ARGS ; fi - if [[ $DEPS == 'lowest' ]]; then travis_retry composer update $COMPOSER_ARGS --prefer-lowest --prefer-stable ; fi - if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry composer require --dev $COMPOSER_ARGS $COVERAGE_DEPS ; fi - stty cols 120 && composer show script: - if [[ $TEST_COVERAGE == 'true' ]]; then composer test-coverage ; else composer test ; fi - if [[ $CS_CHECK == 'true' ]]; then composer cs-check ; fi after_script: - if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry php vendor/bin/php-coveralls -v ; fi notifications: email: false php-zend-code-3.4.1/CHANGELOG.md000066400000000000000000000360111357431215700157760ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file, in reverse chronological order by release. ## 3.4.1 - 2019-12-10 ### Added - [#180](https://github.com/zendframework/zend-code/pull/180) adds support for PHP 7.4. ### Changed - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#179](https://github.com/zendframework/zend-code/pull/179) fixes exception message when invalid value provided in `Zend\Code\Generator\ValueGenerator`. - [#180](https://github.com/zendframework/zend-code/pull/190) fixes PHP 7.4 compatibility. ## 3.4.0 - 2019-10-06 ### Added - [#170](https://github.com/zendframework/zend-code/pull/170) adds class constant visibility modifiers support. - [#169](https://github.com/zendframework/zend-code/pull/169) adds the ability to define declare statements. - [#167](https://github.com/zendframework/zend-code/pull/167) adds the ability to remove doc block of a member. ### Changed - [#166](https://github.com/zendframework/zend-code/pull/166) changes omitting default property value if it is null. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#172](https://github.com/zendframework/zend-code/pull/172) fixes PHP 7.4 compatibility. ## 3.3.2 - 2019-08-31 ### Added - [#162](https://github.com/zendframework/zend-code/pull/162) adds support for PHP 7.3. ### Changed - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#171](https://github.com/zendframework/zend-code/pull/171) changes curly braces in array and string offset access to square brackets in order to prevent issues under the upcoming PHP 7.4 release. - [#164](https://github.com/zendframework/zend-code/pull/164) fixes indentation in multi-level arrays generated by `ValueGenerator`. ## 3.3.1 - 2018-08-13 ### Added - Nothing. ### Changed - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#158](https://github.com/zendframework/zend-code/pull/158) updates several `switch` cases to use `break` instead of `continue` in order to prevent issues under the upcoming PHP 7.3 release. - [#147](https://github.com/zendframework/zend-code/pull/147) fixes the regular expression used for `@var` annotations to allow omission of the variable name. - [#146](https://github.com/zendframework/zend-code/pull/146) updates all `@return` annotations to reflect the correct types returned by each method. - [#144](https://github.com/zendframework/zend-code/pull/144) fixes the class generator such that it now resolves `setExtendedClass()` arguments to aliases provided to the generator. - [#140](https://github.com/zendframework/zend-code/pull/140) fixes `MethodScanner::setVisibility()` such that it no longer casts the provided visibility token to lower case; this fix is necessary, as the method is supposed to expect only the appropriate `T_(PUBLIC|PROTECTED|PRIVATE)` token values, which are integers. - [#140](https://github.com/zendframework/zend-code/pull/140) updates the `MethodScanner::setVisibility()` method to raise a package-specific `InvalidArgumentException` instead of the non-existent package `Exception` class when an invalid visibility is provided. ## 3.3.0 - 2017-10-20 ### Added - [#131](https://github.com/zendframework/zend-code/pull/131) added the ability to omit a parameter type declaration - [#132](https://github.com/zendframework/zend-code/pull/132) added a lightweight `MethodGenerator::copyMethodSignature()` constructor that only copies the method declaration with no body nor docblock. - [#134](https://github.com/zendframework/zend-code/pull/134) short array notation is now used by default for generated array values - [#136](https://github.com/zendframework/zend-code/pull/136) added the ability to specify an `omitdefaultvalue` key when using `ParameterGenerator::fromArray()` ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#130](https://github.com/zendframework/zend-code/pull/130) Updated links to the documentation - [#133](https://github.com/zendframework/zend-code/pull/133) The default value of a `ParameterGenerator` is always a `ValueGenerator` ## 3.2.0 - 2017-07-23 ### Added - [#112](https://github.com/zendframework/zend-code/pull/112) [#110](https://github.com/zendframework/zend-code/pull/110) Introduced support for the PHP `7.2` `object` type-hint - [#41](https://github.com/zendframework/zend-code/pull/41) Added `VarTag` support to the docblock generators and reflectors: allows generating and parsing `@var` tags. - [#113](https://github.com/zendframework/zend-code/pull/113) Added PHP `7.2` to the build matrix - [#114](https://github.com/zendframework/zend-code/pull/114) Increased minimum supported PHP version to `^7.1.0` - [#114](https://github.com/zendframework/zend-code/pull/114) Upgraded PHPUnit dependency to `^6.2.2` - [#121](https://github.com/zendframework/zend-code/pull/121) Imported global functions via `use` statements (experimenting with OpCache OPCODE inlining optimisations) ### Deprecated - Nothing. ### Removed - [#113](https://github.com/zendframework/zend-code/pull/113) [#118](https://github.com/zendframework/zend-code/pull/118) Removed HHVM support - [#122](https://github.com/zendframework/zend-code/pull/122) Removed IRC notifications for pushes/build statuses ### Fixed - [#101](https://github.com/zendframework/zend-code/pull/101) avoid calling `isInternalPhpType` twice in the `TypeGenerator` - [#115](https://github.com/zendframework/zend-code/pull/115) Replaced assertions in the test suite with their static counterparts where applicable - [#120](https://github.com/zendframework/zend-code/pull/120) [#109](https://github.com/zendframework/zend-code/pull/109) [#100](https://github.com/zendframework/zend-code/pull/100) Applied ZendFramework coding standard to the library code - [#119](https://github.com/zendframework/zend-code/pull/119) Corrected test suite errors caused by mismatching parameter order - [#106](https://github.com/zendframework/zend-code/pull/106) - [#107](https://github.com/zendframework/zend-code/pull/107) Minor typing error corrections in documentation and error messages ## 3.1.0 - 2016-10-24 ### Added - [#87](https://github.com/zendframework/zend-code/pull/87) support for PHP 7.1's `void` return type declaration. - [#87](https://github.com/zendframework/zend-code/pull/87) support for PHP 7.1's nullable type declarations. - [#87](https://github.com/zendframework/zend-code/pull/87) support for PHP 7.1's `iterable` type declaration. - [#62](https://github.com/zendframework/zend-code/pull/62) added `Zend\Code\Generator\MethodGenerator#getReturnType()` accessor. - [#68](https://github.com/zendframework/zend-code/pull/68) [#26](https://github.com/zendframework/zend-code/pull/26) added mutators to allow removing/checking for existence of methods, properties, constants, parameters and type declarations across all the code generator API. - [#65](https://github.com/zendframework/zend-code/pull/65) continuous integration testing now checks locked, newest and oldest dependency sets. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - Nothing. ## 3.0.5 - 2016-10-24 ### Added - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#92](https://github.com/zendframework/zend-code/pull/92) corrected `Zend\Code\Scanner\ClassScanner` to detect multiple interface inheritance. - [#95](https://github.com/zendframework/zend-code/pull/95) corrected `Zend\Code\Generator\ParameterGenerator` to allow copying parameter signatures for non-optional parameters that are still nullable via a default `= null` value. - [#94](https://github.com/zendframework/zend-code/pull/94) corrected `Zend\Code\Generator\ValueGenerator` so that class constants can now be generated with arrays as default value (supported since PHP 5.6). ## 3.0.4 - 2016-06-30 ### Added - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#59](https://github.com/zendframework/zend-code/pull/59) fixes an issue with detection of multiple trait `use` statements. - [#75](https://github.com/zendframework/zend-code/pull/75) provides a patch to ensure that `extends` statements qualify the parent class based on the current namespace and/or import statements. ## 3.0.3 - 2016-06-27 ### Added - [#66](https://github.com/zendframework/zend-code/pull/66) publishes the documentation to https://docs.zendframework.com/zend-code/. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#61](https://github.com/zendframework/zend-code/pull/61) fixes an issue with how parameter typehints were generated; previously, fully-qualified class names were not being generated with the leading backslash, causing them to attempt to resolve as if they were relative to the current namespace. - [#69](https://github.com/zendframework/zend-code/pull/69) fixes an issue with how class names under the same namespace are generated when generating typehints, extends, and implements values; they now strip the common namespace from the class name. - [#72](https://github.com/zendframework/zend-code/pull/72) fixes an issue within the `TokenArrayScanner` when scanning closures. ## 3.0.2 - 2016-04-20 ### Added - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#52](https://github.com/zendframework/zend-code/pull/52) updates several dependency constraints: - zend-stdlib now allows either the 2.7 or 3.0 series, as the APIs consumed by zend-code are compatible across versions. - PHP now excludes the 7.0.5 release, as it has known issues in its tokenizer implementation that make the zend-code token scanner unusable. - [#46](https://github.com/zendframework/zend-code/pull/46) updates all generators to use `\n` for line endings in generated code, vs `PHP_EOL`, ensuring cross-platform consistency. ## 3.0.1 - 2016-01-26 ### Added - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#34](https://github.com/zendframework/zend-code/pull/34) method name cannot be optional when adding a method to a class generator. - [#38](https://github.com/zendframework/zend-code/pull/38) PHP_CodeSniffer was moved to dev dependencies ## 3.0.0 - 2016-01-13 ### Changed - [#140](https://github.com/zendframework/zend-code/pull/140) updates the `MethodScanner::setVisibility()` method to raise a package-specific `InvalidArgumentException` instead of the non-existent package `Exception` class when an invalid visibility is provided. This section refers to breaking changes: please refer to [docs/book/migration.md](docs/book/migration.md) for migration instructions. - Types `string`, `int`, `float`, `bool` passed to `Zend\Code\Generator\ParameterGenerator#setType()` are no longer ignored in generated code [#30](https://github.com/zendframework/zend-code/pull/30) - Types declared in DocBlocks are now ignored when creating a `Zend\Code\Generator\ParameterGenerator` via `Zend\Code\Generator\ParameterGenerator::fromReflection()`. [#30](https://github.com/zendframework/zend-code/pull/30) - Type strings are now validated: passing an invalid type to any method in the generator API may lead to a `Zend\Code\Generator\InvalidArgumentException` being thrown. [#30](https://github.com/zendframework/zend-code/pull/30) - `Zend\Code\Generator\ParameterGenerator::$simple` was removed. [#30](https://github.com/zendframework/zend-code/pull/30) - `Zend\Code\Generator\ParameterGenerator#$type` is now a `null|Zend\Code\Generator\TypeGenerator`: was a `string` before. [#30](https://github.com/zendframework/zend-code/pull/30) - `Zend\Code\Generator` type-hints are now always prefixed with the namespace separator `\`. [#30](https://github.com/zendframework/zend-code/pull/30) - `Zend\Code\Reflection\ParameterReflection#getType()` was renamed to `Zend\Code\Reflection\ParameterReflection#detectType()` in order to not override the inherited `ReflectionParameter#getType()`, introduced in PHP 7. [#30](https://github.com/zendframework/zend-code/pull/30) ### Added - PHP 7 return type hints generation support via `Zend\Code\Generator\MethodGenerator#setReturnType()`. [#30](https://github.com/zendframework/zend-code/pull/30) - PHP 7 scalar type hints generation support via `Zend\Code\Generator\ParameterGenerator#setType()` and `Zend\Code\Generator\ParameterGenerator#getType()`. [#30](https://github.com/zendframework/zend-code/pull/30) - PHP 5.6 variadic arguments support via `Zend\Code\Generator\ParameterGenerator#setVariadic()` and `Zend\Code\Generator\ParameterGenerator#getVariadic()`. [#30](https://github.com/zendframework/zend-code/pull/30) - Generation of methods returning by reference is supported via `Zend\Code\Generator\ParameterGenerator#setReturnsReference()`. [#30](https://github.com/zendframework/zend-code/pull/30) ### Deprecated - Nothing. ### Removed - `Zend\Code\ParameterGenerator::$simple` was removed. [#30](https://github.com/zendframework/zend-code/pull/30) ### Fixed - Nothing. ## 2.6.2 - 2015-01-05 ### Added - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#31](https://github.com/zendframework/zend-code/pull/31) updated license year. ## 2.6.2 - 2015-01-05 ### Added - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#31](https://github.com/zendframework/zend-code/pull/31) updated license year. ## 2.6.1 - 2015-11-24 ### Added - Nothing. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#25](https://github.com/zendframework/zend-code/pull/25) changes the `doctrine/common` suggestion/dev-dependency to the more specific `doctrine/annotations` package (which is what is actually consumed). ## 2.6.0 - 2015-11-18 ### Added - [#12](https://github.com/zendframework/zend-code/pull/12) adds the ability to generate arrays using either long/standard syntax (`array(...)`) or short syntax (`[...]`). This can be accomplished by setting the value type to `ValueGenerator::TYPE_ARRAY_SHORT` instead of using `TYPE_ARRAY`. Additionally, you can use `TYPE_ARRAY_LONG` instead of `TYPE_ARRAY`; the two constants are synonyms. - [#11](https://github.com/zendframework/zend-code/pull/11) adds the ability to generate interfaces via the new class `Zend\Code\Generator\InterfaceGenerator`. ### Deprecated - Nothing. ### Removed - Nothing. ### Fixed - [#20](https://github.com/zendframework/zend-code/pull/20) updates the zend-eventmanager dependency to `^2.6|^3.0`, and changes its internal usage to use the `triggerEventUntil()` signature. ## 2.5.3 - 2015-11-18 ### Added - Nothing. ### Deprecated - Nothing. ### Removed - [#10](https://github.com/zendframework/zend-code/pull/10) removes a development dependency on zendframework/zend-version. - [#23](https://github.com/zendframework/zend-code/pull/23) removes a requirement on zendframework/zend-stdlib. This results in a slight change in `Zend\Code\Generator\ValueGenerator`: `setConstants()` and `getConstants()` can now receive/emit *either* an SPL `ArrayObject` or `Zend\Stdlib\ArrayObject`. Since these are functionally equivalent, however, you will experience no change in behavior. ### Fixed - Nothing. php-zend-code-3.4.1/LICENSE.md000066400000000000000000000027541357431215700156000ustar00rootroot00000000000000Copyright (c) 2005-2019, Zend Technologies USA, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of Zend Technologies USA, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. php-zend-code-3.4.1/README.md000066400000000000000000000016471357431215700154530ustar00rootroot00000000000000# zend-code [![Build Status](https://secure.travis-ci.org/zendframework/zend-code.svg?branch=master)](https://secure.travis-ci.org/zendframework/zend-code) [![Coverage Status](https://coveralls.io/repos/github/zendframework/zend-code/badge.svg?branch=master)](https://coveralls.io/github/zendframework/zend-code?branch=master) `Zend\Code\Generator` provides facilities to generate arbitrary code using an object-oriented interface, both to create new code as well as to update existing code. While the current implementation is limited to generating PHP code, you can easily extend the base class in order to provide code generation for other tasks: JavaScript, configuration files, apache vhosts, etc. - File issues at https://github.com/zendframework/zend-code/issues - Documentation is at https://docs.zendframework.com/zend-code/ - Migration documentation from v2 to v3 is at https://docs.zendframework.com/zend-code/migration/ php-zend-code-3.4.1/composer.json000066400000000000000000000036701357431215700167140ustar00rootroot00000000000000{ "name": "zendframework/zend-code", "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", "license": "BSD-3-Clause", "keywords": [ "zf", "zendframework", "code" ], "support": { "docs": "https://docs.zendframework.com/zend-code/", "issues": "https://github.com/zendframework/zend-code/issues", "source": "https://github.com/zendframework/zend-code", "rss": "https://github.com/zendframework/zend-code/releases.atom", "chat": "https://zendframework-slack.herokuapp.com", "forum": "https://discourse.zendframework.com/c/questions/components" }, "require": { "php": "^7.1", "zendframework/zend-eventmanager": "^2.6 || ^3.0" }, "require-dev": { "ext-phar": "*", "doctrine/annotations": "^1.7", "phpunit/phpunit": "^7.5.16 || ^8.4", "zendframework/zend-coding-standard": "^1.0", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "conflict": { "phpspec/prophecy": "<1.9.0" }, "suggest": { "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", "zendframework/zend-stdlib": "Zend\\Stdlib component" }, "autoload": { "psr-4": { "Zend\\Code\\": "src/" } }, "autoload-dev": { "psr-4": { "ZendTest\\Code\\": "test/" } }, "config": { "sort-packages": true }, "extra": { "branch-alias": { "dev-master": "3.4.x-dev", "dev-develop": "3.5.x-dev", "dev-dev-4.0": "4.0.x-dev" } }, "scripts": { "check": [ "@cs-check", "@test" ], "cs-check": "phpcs", "cs-fix": "phpcbf", "test": "phpunit --colors=always", "test-coverage": "phpunit --colors=always --coverage-clover clover.xml" } } php-zend-code-3.4.1/composer.lock000066400000000000000000002022571357431215700166750ustar00rootroot00000000000000{ "_readme": [ "This file locks the dependencies of your project to a known state", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], "content-hash": "19b802ccaf8f069c8d62e3e589500bad", "packages": [ { "name": "zendframework/zend-eventmanager", "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-eventmanager.git", "reference": "a5e2583a211f73604691586b8406ff7296a946dd" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/a5e2583a211f73604691586b8406ff7296a946dd", "reference": "a5e2583a211f73604691586b8406ff7296a946dd", "shasum": "" }, "require": { "php": "^5.6 || ^7.0" }, "require-dev": { "athletic/athletic": "^0.1", "container-interop/container-interop": "^1.1.0", "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", "zendframework/zend-coding-standard": "~1.0.0", "zendframework/zend-stdlib": "^2.7.3 || ^3.0" }, "suggest": { "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature", "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.2-dev", "dev-develop": "3.3-dev" } }, "autoload": { "psr-4": { "Zend\\EventManager\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "description": "Trigger and listen to events within a PHP application", "homepage": "https://github.com/zendframework/zend-eventmanager", "keywords": [ "event", "eventmanager", "events", "zf2" ], "time": "2018-04-25T15:33:34+00:00" } ], "packages-dev": [ { "name": "doctrine/annotations", "version": "v1.8.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", "shasum": "" }, "require": { "doctrine/lexer": "1.*", "php": "^7.1" }, "require-dev": { "doctrine/cache": "1.*", "phpunit/phpunit": "^7.5" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.7.x-dev" } }, "autoload": { "psr-4": { "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, { "name": "Roman Borschel", "email": "roman@code-factory.org" }, { "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" } ], "description": "Docblock Annotations Parser", "homepage": "http://www.doctrine-project.org", "keywords": [ "annotations", "docblock", "parser" ], "time": "2019-10-01T18:55:10+00:00" }, { "name": "doctrine/instantiator", "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "doctrine/coding-standard": "^6.0", "ext-pdo": "*", "ext-phar": "*", "phpbench/phpbench": "^0.13", "phpstan/phpstan-phpunit": "^0.11", "phpstan/phpstan-shim": "^0.11", "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.2.x-dev" } }, "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", "homepage": "http://ocramius.github.com/" } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], "time": "2019-10-21T16:45:58+00:00" }, { "name": "doctrine/lexer", "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", "shasum": "" }, "require": { "php": "^7.2" }, "require-dev": { "doctrine/coding-standard": "^6.0", "phpstan/phpstan": "^0.11.8", "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.2.x-dev" } }, "autoload": { "psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, { "name": "Roman Borschel", "email": "roman@code-factory.org" }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" } ], "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", "homepage": "https://www.doctrine-project.org/projects/lexer.html", "keywords": [ "annotations", "docblock", "lexer", "parser", "php" ], "time": "2019-10-30T14:39:59+00:00" }, { "name": "myclabs/deep-copy", "version": "1.9.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", "shasum": "" }, "require": { "php": "^7.1" }, "replace": { "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { "psr-4": { "DeepCopy\\": "src/DeepCopy/" }, "files": [ "src/DeepCopy/deep_copy.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "description": "Create deep copies (clones) of your objects", "keywords": [ "clone", "copy", "duplicate", "object", "object graph" ], "time": "2019-08-09T12:45:53+00:00" }, { "name": "phar-io/manifest", "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", "phar-io/version": "^2.0", "php": "^5.6 || ^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Arne Blankerts", "email": "arne@blankerts.de", "role": "Developer" }, { "name": "Sebastian Heuer", "email": "sebastian@phpeople.de", "role": "Developer" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "Developer" } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { "php": "^5.6 || ^7.0" }, "type": "library", "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Arne Blankerts", "email": "arne@blankerts.de", "role": "Developer" }, { "name": "Sebastian Heuer", "email": "sebastian@phpeople.de", "role": "Developer" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "Developer" } ], "description": "Library for handling version information and constraints", "time": "2018-07-08T19:19:57+00:00" }, { "name": "phpdocumentor/reflection-common", "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { "php": ">=7.1" }, "require-dev": { "phpunit/phpunit": "~6" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Jaap van Otterdijk", "email": "opensource@ijaap.nl" } ], "description": "Common reflection classes used by phpdocumentor to reflect the code structure", "homepage": "http://www.phpdoc.org", "keywords": [ "FQSEN", "phpDocumentor", "phpdoc", "reflection", "static analysis" ], "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", "version": "4.3.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", "shasum": "" }, "require": { "php": "^7.0", "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", "webmozart/assert": "^1.0" }, "require-dev": { "doctrine/instantiator": "^1.0.5", "mockery/mockery": "^1.0", "phpunit/phpunit": "^6.4" }, "type": "library", "extra": { "branch-alias": { "dev-master": "4.x-dev" } }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": [ "src/" ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Mike van Riel", "email": "me@mikevanriel.com" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "time": "2019-09-12T14:27:41+00:00" }, { "name": "phpdocumentor/type-resolver", "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "shasum": "" }, "require": { "php": "^7.1", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { "ext-tokenizer": "^7.1", "mockery/mockery": "~1", "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.x-dev" } }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Mike van Riel", "email": "me@mikevanriel.com" } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "time": "2019-08-22T18:11:29+00:00" }, { "name": "phpspec/prophecy", "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", "sebastian/comparator": "^1.1|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.8.x-dev" } }, "autoload": { "psr-4": { "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Konstantin Kudryashov", "email": "ever.zet@gmail.com", "homepage": "http://everzet.com" }, { "name": "Marcello Duarte", "email": "marcello.duarte@gmail.com" } ], "description": "Highly opinionated mocking framework for PHP 5.3+", "homepage": "https://github.com/phpspec/prophecy", "keywords": [ "Double", "Dummy", "fake", "mock", "spy", "stub" ], "time": "2019-10-03T11:07:50+00:00" }, { "name": "phpunit/php-code-coverage", "version": "7.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", "php": "^7.2", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", "phpunit/php-token-stream": "^3.1.1", "sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1.3" }, "require-dev": { "phpunit/phpunit": "^8.2.2" }, "suggest": { "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { "dev-master": "7.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", "homepage": "https://github.com/sebastianbergmann/php-code-coverage", "keywords": [ "coverage", "testing", "xunit" ], "time": "2019-11-20T13:55:58+00:00" }, { "name": "phpunit/php-file-iterator", "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", "reference": "050bedf145a257b1ff02746c31894800e5122946" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", "reference": "050bedf145a257b1ff02746c31894800e5122946", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "FilterIterator implementation that filters files based on a list of suffixes.", "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", "keywords": [ "filesystem", "iterator" ], "time": "2018-09-13T20:33:42+00:00" }, { "name": "phpunit/php-text-template", "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "shasum": "" }, "require": { "php": ">=5.3.3" }, "type": "library", "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "Simple template engine.", "homepage": "https://github.com/sebastianbergmann/php-text-template/", "keywords": [ "template" ], "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.1-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "Utility class for timing", "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ "timer" ], "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.1-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Wrapper around PHP's tokenizer extension.", "homepage": "https://github.com/sebastianbergmann/php-token-stream/", "keywords": [ "tokenizer" ], "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", "version": "8.5.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", "reference": "3ee1c1fd6fc264480c25b6fb8285edefe1702dab" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3ee1c1fd6fc264480c25b6fb8285edefe1702dab", "reference": "3ee1c1fd6fc264480c25b6fb8285edefe1702dab", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2.0", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.9.1", "phar-io/manifest": "^1.0.3", "phar-io/version": "^2.0.1", "php": "^7.2", "phpspec/prophecy": "^1.8.1", "phpunit/php-code-coverage": "^7.0.7", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", "phpunit/php-timer": "^2.1.2", "sebastian/comparator": "^3.0.2", "sebastian/diff": "^3.0.2", "sebastian/environment": "^4.2.2", "sebastian/exporter": "^3.1.1", "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", "sebastian/resource-operations": "^2.0.1", "sebastian/type": "^1.1.3", "sebastian/version": "^2.0.1" }, "require-dev": { "ext-pdo": "*" }, "suggest": { "ext-soap": "*", "ext-xdebug": "*", "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" ], "type": "library", "extra": { "branch-alias": { "dev-master": "8.5-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "The PHP Unit Testing framework.", "homepage": "https://phpunit.de/", "keywords": [ "phpunit", "testing", "xunit" ], "time": "2019-12-06T05:41:38+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", "shasum": "" }, "require": { "php": "^5.6 || ^7.0" }, "require-dev": { "phpunit/phpunit": "^5.7 || ^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "time": "2017-03-04T06:30:41+00:00" }, { "name": "sebastian/comparator", "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "shasum": "" }, "require": { "php": "^7.1", "sebastian/diff": "^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" }, { "name": "Volker Dusch", "email": "github@wallbash.com" }, { "name": "Bernhard Schussek", "email": "bschussek@2bepublished.at" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Provides the functionality to compare PHP values for equality", "homepage": "https://github.com/sebastianbergmann/comparator", "keywords": [ "comparator", "compare", "equality" ], "time": "2018-07-12T15:12:46+00:00" }, { "name": "sebastian/diff", "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.5 || ^8.0", "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Kore Nordmann", "email": "mail@kore-nordmann.de" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ "diff", "udiff", "unidiff", "unified diff" ], "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.5" }, "suggest": { "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { "dev-master": "4.2-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Provides functionality to handle HHVM/PHP environments", "homepage": "http://www.github.com/sebastianbergmann/environment", "keywords": [ "Xdebug", "environment", "hhvm" ], "time": "2019-11-20T08:46:58+00:00" }, { "name": "sebastian/exporter", "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { "php": "^7.0", "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-mbstring": "*", "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.1.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" }, { "name": "Volker Dusch", "email": "github@wallbash.com" }, { "name": "Adam Harvey", "email": "aharvey@php.net" }, { "name": "Bernhard Schussek", "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", "homepage": "http://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], "time": "2019-09-14T09:02:43+00:00" }, { "name": "sebastian/global-state", "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", "shasum": "" }, "require": { "php": "^7.2", "sebastian/object-reflector": "^1.1.1", "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-dom": "*", "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Snapshotting of global state", "homepage": "http://www.github.com/sebastianbergmann/global-state", "keywords": [ "global state" ], "time": "2019-02-01T05:30:01+00:00" }, { "name": "sebastian/object-enumerator", "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", "shasum": "" }, "require": { "php": "^7.0", "sebastian/object-reflector": "^1.1.1", "sebastian/recursion-context": "^3.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "time": "2017-08-03T12:35:26+00:00" }, { "name": "sebastian/object-reflector", "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", "reference": "773f97c67f28de00d397be301821b06708fca0be" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", "reference": "773f97c67f28de00d397be301821b06708fca0be", "shasum": "" }, "require": { "php": "^7.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.1-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", "time": "2017-03-29T09:07:27+00:00" }, { "name": "sebastian/recursion-context", "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", "shasum": "" }, "require": { "php": "^7.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, { "name": "Adam Harvey", "email": "aharvey@php.net" } ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", "time": "2017-03-03T06:23:57+00:00" }, { "name": "sebastian/resource-operations", "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "shasum": "" }, "require": { "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "time": "2018-10-04T04:07:39+00:00" }, { "name": "sebastian/type", "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", "shasum": "" }, "require": { "php": "^7.2" }, "require-dev": { "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.1-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "Collection of value objects that represent the types of the PHP type system", "homepage": "https://github.com/sebastianbergmann/type", "time": "2019-07-02T08:10:15+00:00" }, { "name": "sebastian/version", "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", "shasum": "" }, "require": { "php": ">=5.6" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", "time": "2016-10-03T07:35:21+00:00" }, { "name": "squizlabs/php_codesniffer", "version": "2.9.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", "reference": "2acf168de78487db620ab4bc524135a13cfe6745" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/2acf168de78487db620ab4bc524135a13cfe6745", "reference": "2acf168de78487db620ab4bc524135a13cfe6745", "shasum": "" }, "require": { "ext-simplexml": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", "php": ">=5.1.2" }, "require-dev": { "phpunit/phpunit": "~4.0" }, "bin": [ "scripts/phpcs", "scripts/phpcbf" ], "type": "library", "extra": { "branch-alias": { "dev-master": "2.x-dev" } }, "autoload": { "classmap": [ "CodeSniffer.php", "CodeSniffer/CLI.php", "CodeSniffer/Exception.php", "CodeSniffer/File.php", "CodeSniffer/Fixer.php", "CodeSniffer/Report.php", "CodeSniffer/Reporting.php", "CodeSniffer/Sniff.php", "CodeSniffer/Tokens.php", "CodeSniffer/Reports/", "CodeSniffer/Tokenizers/", "CodeSniffer/DocGenerators/", "CodeSniffer/Standards/AbstractPatternSniff.php", "CodeSniffer/Standards/AbstractScopeSniff.php", "CodeSniffer/Standards/AbstractVariableSniff.php", "CodeSniffer/Standards/IncorrectPatternException.php", "CodeSniffer/Standards/Generic/Sniffs/", "CodeSniffer/Standards/MySource/Sniffs/", "CodeSniffer/Standards/PEAR/Sniffs/", "CodeSniffer/Standards/PSR1/Sniffs/", "CodeSniffer/Standards/PSR2/Sniffs/", "CodeSniffer/Standards/Squiz/Sniffs/", "CodeSniffer/Standards/Zend/Sniffs/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Greg Sherwood", "role": "lead" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", "homepage": "http://www.squizlabs.com/php-codesniffer", "keywords": [ "phpcs", "standards" ], "time": "2018-11-07T22:31:41+00:00" }, { "name": "symfony/polyfill-ctype", "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", "shasum": "" }, "require": { "php": ">=5.3.3" }, "suggest": { "ext-ctype": "For best performance" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.13-dev" } }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, "files": [ "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", "ctype", "polyfill", "portable" ], "time": "2019-11-27T13:56:44+00:00" }, { "name": "theseer/tokenizer", "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", "php": "^7.0" }, "type": "library", "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Arne Blankerts", "email": "arne@blankerts.de", "role": "Developer" } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "time": "2019-06-13T22:48:21+00:00" }, { "name": "webmozart/assert", "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "vimeo/psalm": "<3.6.0" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Bernhard Schussek", "email": "bschussek@gmail.com" } ], "description": "Assertions to validate method input/output with nice error messages.", "keywords": [ "assert", "check", "validate" ], "time": "2019-11-24T13:36:37+00:00" }, { "name": "zendframework/zend-coding-standard", "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-coding-standard.git", "reference": "893316d2904e93f1c74c1384b6d7d57778299cb6" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/zendframework/zend-coding-standard/zipball/893316d2904e93f1c74c1384b6d7d57778299cb6", "reference": "893316d2904e93f1c74c1384b6d7d57778299cb6", "shasum": "" }, "require": { "squizlabs/php_codesniffer": "^2.7" }, "type": "library", "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "description": "Zend Framework coding standard", "keywords": [ "Coding Standard", "zf" ], "time": "2016-11-09T21:30:43+00:00" }, { "name": "zendframework/zend-stdlib", "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-stdlib.git", "reference": "66536006722aff9e62d1b331025089b7ec71c065" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/66536006722aff9e62d1b331025089b7ec71c065", "reference": "66536006722aff9e62d1b331025089b7ec71c065", "shasum": "" }, "require": { "php": "^5.6 || ^7.0" }, "require-dev": { "phpbench/phpbench": "^0.13", "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", "zendframework/zend-coding-standard": "~1.0.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.2.x-dev", "dev-develop": "3.3.x-dev" } }, "autoload": { "psr-4": { "Zend\\Stdlib\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "description": "SPL extensions, array utilities, error handlers, and more", "keywords": [ "ZendFramework", "stdlib", "zf" ], "time": "2018-08-28T21:34:05+00:00" } ], "aliases": [], "minimum-stability": "stable", "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { "php": "^7.1" }, "platform-dev": { "ext-phar": "*" } } php-zend-code-3.4.1/docs/000077500000000000000000000000001357431215700151145ustar00rootroot00000000000000php-zend-code-3.4.1/docs/CODE_OF_CONDUCT.md000066400000000000000000000044741357431215700177240ustar00rootroot00000000000000# Contributor Code of Conduct This project adheres to [The Code Manifesto](http://codemanifesto.com) as its guidelines for contributor interactions. ## The Code Manifesto We want to work in an ecosystem that empowers developers to reach their potential — one that encourages growth and effective collaboration. A space that is safe for all. A space such as this benefits everyone that participates in it. It encourages new developers to enter our field. It is through discussion and collaboration that we grow, and through growth that we improve. In the effort to create such a place, we hold to these values: 1. **Discrimination limits us.** This includes discrimination on the basis of race, gender, sexual orientation, gender identity, age, nationality, technology and any other arbitrary exclusion of a group of people. 2. **Boundaries honor us.** Your comfort levels are not everyone’s comfort levels. Remember that, and if brought to your attention, heed it. 3. **We are our biggest assets.** None of us were born masters of our trade. Each of us has been helped along the way. Return that favor, when and where you can. 4. **We are resources for the future.** As an extension of #3, share what you know. Make yourself a resource to help those that come after you. 5. **Respect defines us.** Treat others as you wish to be treated. Make your discussions, criticisms and debates from a position of respectfulness. Ask yourself, is it true? Is it necessary? Is it constructive? Anything less is unacceptable. 6. **Reactions require grace.** Angry responses are valid, but abusive language and vindictive actions are toxic. When something happens that offends you, handle it assertively, but be respectful. Escalate reasonably, and try to allow the offender an opportunity to explain themselves, and possibly correct the issue. 7. **Opinions are just that: opinions.** Each and every one of us, due to our background and upbringing, have varying opinions. The fact of the matter, is that is perfectly acceptable. Remember this: if you respect your own opinions, you should respect the opinions of others. 8. **To err is human.** You might not intend it, but mistakes do happen and contribute to build experience. Tolerate honest mistakes, and don't hesitate to apologize if you make one yourself. php-zend-code-3.4.1/docs/CONTRIBUTING.md000066400000000000000000000123731357431215700173530ustar00rootroot00000000000000# CONTRIBUTING ## RESOURCES If you wish to contribute to this project, please be sure to read/subscribe to the following resources: - [Coding Standards](https://github.com/zendframework/zend-coding-standard) - [Forums](https://discourse.zendframework.com/c/contributors) - [Chat](https://zendframework-slack.herokuapp.com) - [Code of Conduct](CODE_OF_CONDUCT.md) If you are working on new features or refactoring [create a proposal](https://github.com/zendframework/zend-code/issues/new). ## RUNNING TESTS To run tests: - Clone the repository: ```console $ git clone git://github.com/zendframework/zend-code.git $ cd zend-code ``` - Install dependencies via composer: ```console $ composer install ``` If you don't have `composer` installed, please download it from https://getcomposer.org/download/ - Run the tests using the "test" command shipped in the `composer.json`: ```console $ composer test ``` You can turn on conditional tests with the `phpunit.xml` file. To do so: - Copy `phpunit.xml.dist` file to `phpunit.xml` - Edit `phpunit.xml` to enable any specific functionality you want to test, as well as to provide test values to utilize. ## Running Coding Standards Checks First, ensure you've installed dependencies via composer, per the previous section on running tests. To run CS checks only: ```console $ composer cs-check ``` To attempt to automatically fix common CS issues: ```console $ composer cs-fix ``` If the above fixes any CS issues, please re-run the tests to ensure they pass, and make sure you add and commit the changes after verification. ## Recommended Workflow for Contributions Your first step is to establish a public repository from which we can pull your work into the master repository. We recommend using [GitHub](https://github.com), as that is where the component is already hosted. 1. Setup a [GitHub account](https://github.com/), if you haven't yet 2. Fork the repository (https://github.com/zendframework/zend-code) 3. Clone the canonical repository locally and enter it. ```console $ git clone git://github.com/zendframework/zend-code.git $ cd zend-code ``` 4. Add a remote to your fork; substitute your GitHub username in the command below. ```console $ git remote add {username} git@github.com:{username}/zend-code.git $ git fetch {username} ``` ### Keeping Up-to-Date Periodically, you should update your fork or personal repository to match the canonical ZF repository. Assuming you have setup your local repository per the instructions above, you can do the following: ```console $ git checkout master $ git fetch origin $ git rebase origin/master # OPTIONALLY, to keep your remote up-to-date - $ git push {username} master:master ``` If you're tracking other branches -- for example, the "develop" branch, where new feature development occurs -- you'll want to do the same operations for that branch; simply substitute "develop" for "master". ### Working on a patch We recommend you do each new feature or bugfix in a new branch. This simplifies the task of code review as well as the task of merging your changes into the canonical repository. A typical workflow will then consist of the following: 1. Create a new local branch based off either your master or develop branch. 2. Switch to your new local branch. (This step can be combined with the previous step with the use of `git checkout -b`.) 3. Do some work, commit, repeat as necessary. 4. Push the local branch to your remote repository. 5. Send a pull request. The mechanics of this process are actually quite trivial. Below, we will create a branch for fixing an issue in the tracker. ```console $ git checkout -b hotfix/9295 Switched to a new branch 'hotfix/9295' ``` ... do some work ... ```console $ git commit ``` ... write your log message ... ```console $ git push {username} hotfix/9295:hotfix/9295 Counting objects: 38, done. Delta compression using up to 2 threads. Compression objects: 100% (18/18), done. Writing objects: 100% (20/20), 8.19KiB, done. Total 20 (delta 12), reused 0 (delta 0) To ssh://git@github.com/{username}/zend-code.git b5583aa..4f51698 HEAD -> master ``` To send a pull request, you have two options. If using GitHub, you can do the pull request from there. Navigate to your repository, select the branch you just created, and then select the "Pull Request" button in the upper right. Select the user/organization "zendframework" (or whatever the upstream organization is) as the recipient. #### What branch to issue the pull request against? Which branch should you issue a pull request against? - For fixes against the stable release, issue the pull request against the "master" branch. - For new features, or fixes that introduce new elements to the public API (such as new public methods or properties), issue the pull request against the "develop" branch. ### Branch Cleanup As you might imagine, if you are a frequent contributor, you'll start to get a ton of branches both locally and on your remote. Once you know that your changes have been accepted to the master repository, we suggest doing some cleanup of these branches. - Local branch cleanup ```console $ git branch -d ``` - Remote branch removal ```console $ git push {username} : ``` php-zend-code-3.4.1/docs/ISSUE_TEMPLATE.md000066400000000000000000000013611357431215700176220ustar00rootroot00000000000000 - [ ] I was not able to find an [open](https://github.com/zendframework/zend-code/issues?q=is%3Aopen) or [closed](https://github.com/zendframework/zend-code/issues?q=is%3Aclosed) issue matching what I'm seeing. - [ ] This is not a question. (Questions should be asked on [chat](https://zendframework.slack.com/) ([Signup here](https://zendframework-slack.herokuapp.com/)) or our [forums](https://discourse.zendframework.com/).) Provide a narrative description of what you are trying to accomplish. ### Code to reproduce the issue ```php ``` ### Expected results ### Actual results php-zend-code-3.4.1/docs/PULL_REQUEST_TEMPLATE.md000066400000000000000000000021741357431215700207210ustar00rootroot00000000000000Provide a narrative description of what you are trying to accomplish: - [ ] Are you fixing a bug? - [ ] Detail how the bug is invoked currently. - [ ] Detail the original, incorrect behavior. - [ ] Detail the new, expected behavior. - [ ] Base your feature on the `master` branch, and submit against that branch. - [ ] Add a regression test that demonstrates the bug, and proves the fix. - [ ] Add a `CHANGELOG.md` entry for the fix. - [ ] Are you creating a new feature? - [ ] Why is the new feature needed? What purpose does it serve? - [ ] How will users use the new feature? - [ ] Base your feature on the `develop` branch, and submit against that branch. - [ ] Add only one feature per pull request; split multiple features over multiple pull requests - [ ] Add tests for the new feature. - [ ] Add documentation for the new feature. - [ ] Add a `CHANGELOG.md` entry for the new feature. - [ ] Is this related to quality assurance? - [ ] Is this related to documentation? php-zend-code-3.4.1/docs/SUPPORT.md000066400000000000000000000017451357431215700166210ustar00rootroot00000000000000# Getting Support Zend Framework offers three support channels: - For real-time questions, use our [chat](https://zendframework-slack.herokuapp.com) - For detailed questions (e.g., those requiring examples) use our [forums](https://discourse.zendframework.com/c/questions/components) - To report issues, use this repository's [issue tracker](https://github.com/zendframework/zend-code/issues/new) **DO NOT** use the issue tracker to ask questions; use chat or the forums for that. Questions posed to the issue tracker will be closed. When reporting an issue, please include the following details: - A narrative description of what you are trying to accomplish. - The minimum code necessary to reproduce the issue. - The expected results of exercising that code. - The actual results received. We may ask for additional details: what version of the library you are using, and what PHP version was used to reproduce the issue. You may also submit a failing test case as a pull request. php-zend-code-3.4.1/docs/book/000077500000000000000000000000001357431215700160465ustar00rootroot00000000000000php-zend-code-3.4.1/docs/book/generator/000077500000000000000000000000001357431215700200345ustar00rootroot00000000000000php-zend-code-3.4.1/docs/book/generator/bookdown.json000066400000000000000000000002411357431215700225460ustar00rootroot00000000000000{ "title": "zend-code Generator Component", "content": [ {"Intro": "intro.md"}, {"Examples": "examples.md"}, {"Reference": "reference.md"} ] } php-zend-code-3.4.1/docs/book/generator/examples.md000066400000000000000000000214761357431215700222060ustar00rootroot00000000000000# Zend\\Code\\Generator Examples ## Generating PHP classes The following example generates an empty class with a class-level DocBlock. ```php use Zend\Code\Generator\ClassGenerator; use Zend\Code\Generator\DocBlockGenerator; $foo = new ClassGenerator(); $docblock = DocBlockGenerator::fromArray([ 'shortDescription' => 'Sample generated class', 'longDescription' => 'This is a class generated with Zend\Code\Generator.', 'tags' => [ [ 'name' => 'version', 'description' => '$Rev:$', ], [ 'name' => 'license', 'description' => 'New BSD', ], ], ]); $foo->setName('Foo') ->setDocblock($docblock); echo $foo->generate(); ``` The above code will result in the following: ```php /** * Sample generated class * * This is a class generated with Zend\Code\Generator. * * @version $Rev:$ * @license New BSD * */ class Foo { } ``` ### Generating PHP classes with class properties Building on the previous example, we now add properties to our generated class. ```php use Zend\Code\Generator\ClassGenerator; use Zend\Code\Generator\DocBlockGenerator; use Zend\Code\Generator\PropertyGenerator; $foo = new ClassGenerator(); $docblock = DocBlockGenerator::fromArray([ 'shortDescription' => 'Sample generated class', 'longDescription' => 'This is a class generated with Zend\Code\Generator.', 'tags' => [ [ 'name' => 'version', 'description' => '$Rev:$', ], [ 'name' => 'license', 'description' => 'New BSD', ], ], ]); $foo->setName('Foo') ->setDocblock($docblock) ->addProperties([ ['_bar', 'baz', PropertyGenerator::FLAG_PROTECTED], ['baz', 'bat', PropertyGenerator::FLAG_PUBLIC] ]) ->addConstants([ ['bat', 'foobarbazbat'] ]); echo $foo->generate(); ``` The above results in the following class definition: ```php /** * Sample generated class * * This is a class generated with Zend\Code\Generator. * * @version $Rev:$ * @license New BSD * */ class Foo { protected $_bar = 'baz'; public $baz = 'bat'; const bat = 'foobarbazbat'; } ``` ### Generating PHP classes with class methods `Zend\Code\Generator\ClassGenerator` allows you to attach methods with optional content to your classes. Methods may be attached as either arrays or concrete `Zend\Code\Generator\MethodGenerator` instances. ```php use Zend\Code\Generator\ClassGenerator; use Zend\Code\Generator\DocBlockGenerator; use Zend\Code\Generator\DocBlock\Tag; use Zend\Code\Generator\MethodGenerator; use Zend\Code\Generator\PropertyGenerator; $foo = new ClassGenerator(); $docblock = DocBlockGenerator::fromArray([ 'shortDescription' => 'Sample generated class', 'longDescription' => 'This is a class generated with Zend\Code\Generator.', 'tags' => [ [ 'name' => 'version', 'description' => '$Rev:$', ], [ 'name' => 'license', 'description' => 'New BSD', ], ], ]); $foo->setName('Foo') ->setDocblock($docblock) ->addProperties([ ['_bar', 'baz', PropertyGenerator::FLAG_PROTECTED], ['baz', 'bat', PropertyGenerator::FLAG_PUBLIC] ]) ->addConstants([ ['bat', 'foobarbazbat', PropertyGenerator::FLAG_CONSTANT] ]) ->addMethods([ // Method passed as array MethodGenerator::fromArray([ 'name' => 'setBar', 'parameters' => ['bar'], 'body' => '$this->_bar = $bar;' . "\n" . 'return $this;', 'docblock' => DocBlockGenerator::fromArray([ 'shortDescription' => 'Set the bar property', 'longDescription' => null, 'tags' => [ new Tag\ParamTag([ 'paramName' => 'bar', 'datatype' => 'string' ]), new Tag\ReturnTag([ 'datatype' => 'string', ]), ], ]), ]), // Method passed as concrete instance new MethodGenerator( 'getBar', [], MethodGenerator::FLAG_PUBLIC, 'return $this->_bar;', DocBlockGenerator::fromArray([ 'shortDescription' => 'Retrieve the bar property', 'longDescription' => null, 'tags' => [ new Tag\ReturnTag([ 'datatype' => 'string|null', ]), ], ]) ), ]); echo $foo->generate(); ``` The above generates the following output: ```php /** * Sample generated class * * This is a class generated with Zend\Code\Generator. * * @version $Rev:$ * @license New BSD */ class Foo { protected $_bar = 'baz'; public $baz = 'bat'; const bat = 'foobarbazbat'; /** * Set the bar property * * @param string bar * @return string */ public function setBar($bar) { $this->_bar = $bar; return $this; } /** * Retrieve the bar property * * @return string|null */ public function getBar() { return $this->_bar; } } ``` ## Generating PHP files `Zend\Code\Generator\FileGenerator` can be used to generate the contents of a *PHP* file. You can include classes as well as arbitrary content body. When attaching classes, you should attach either concrete `Zend\Code\Generator\ClassGenerator` instances or an array defining the class. In the example below, we will assume you've defined `$foo` per one of the class definitions in a previous example. ```php use Zend\Code\Generator\DocBlockGenerator; use Zend\Code\Generator\FileGenerator; $file = FileGenerator::fromArray([ 'classes' => [$foo], 'docblock' => DocBlockGenerator::fromArray([ 'shortDescription' => 'Foo class file', 'longDescription' => null, 'tags' => [ [ 'name' => 'license', 'description' => 'New BSD', ], ], ]), 'body' => 'define(\'APPLICATION_ENV\', \'testing\');', ]); ``` Calling `generate()` will generate the code -- but not write it to a file. You will need to capture the contents and write them to a file yourself. As an example: ```php $code = $file->generate(); file_put_contents('Foo.php', $code); ``` The above will generate the following file: ```php _bar = $bar; return $this; } /** * Retrieve the bar property * * @return string|null */ public function getBar() { return $this->_bar; } } define('APPLICATION_ENV', 'testing'); ``` ## Add code to existing PHP files and classes ### Seeding PHP file code generation via reflection You can add *PHP* code to an existing *PHP* file using the code generator. To do so, you need to first do reflection on it. The static method `fromReflectedFileName()` allows you to do this. ```php $generator = Zend\Code\Generator\FileGenerator::fromReflectedFileName($path); $generator->setBody("\$foo->bar();"); file_put_contents($path, $generator->generate()); ``` ### Seeding PHP class generation via reflection You may add code to an existing class. To do so, first use the static `fromReflection()` method to map the class into a generator object. From there, you may add additional properties or methods, and then regenerate the class. ```php use Zend\Code\Generator\ClassGenerator; use Zend\Code\Generator\DocBlockGenerator; use Zend\Code\Generator\DocBlock\Tag; use Zend\Code\Generator\MethodGenerator; use Zend\Code\Reflection\ClassReflection; $generator = ClassGenerator::fromReflection( new ClassReflection($class) ); $generator->addMethod( 'setBaz', ['baz'], MethodGenerator::FLAG_PUBLIC, '$this->_baz = $baz;' . "\n" . 'return $this;', DocBlockGenerator::fromArray([ 'shortDescription' => 'Set the baz property', 'longDescription' => null, 'tags' => [ new Tag\ParamTag([ 'paramName' => 'baz', 'datatype' => 'string' ]), new Tag\ReturnTag([ 'datatype' => 'string', ]), ], ]) ); $code = $generator->generate(); ``` php-zend-code-3.4.1/docs/book/generator/intro.md000066400000000000000000000065221357431215700215160ustar00rootroot00000000000000# Introduction `Zend\Code\Generator` provides facilities to generate arbitrary code using an object-oriented interface, both to create new code as well as to update existing code. While the current implementation is limited to generating *PHP* code, you can easily extend the base class in order to provide code generation for other tasks: JavaScript, configuration files, apache vhosts, etc. ## Theory of Operation In the most typical use case, you will simply instantiate a code generator class and either pass it the appropriate configuration or configure it after instantiation. To generate the code, you will simply echo the object or call its `generate()` method. ```php // Passing configuration to the constructor: $file = new Zend\Code\Generator\FileGenerator(array( 'classes' => array( new Zend\Code\Generator\ClassGenerator( 'World', // name null, // namespace null, // flags null, // extends array(), // interfaces array(), // properties array( new Zend\Code\Generator\MethodGenerator( 'hello', // name array(), // parameters 'public', // visibility 'echo \'Hello world!\';' // body ), ) ), ), )); // Render the generated file echo $file->generate(); // or write it to a file: file_put_contents('World.php', $file->generate()); // OR // Configuring after instantiation $method = new Zend\Code\Generator\MethodGenerator(); $method->setName('hello') ->setBody('echo \'Hello world!\';'); $class = new Zend\Code\Generator\ClassGenerator(); $class->setName('World') ->addMethodFromGenerator($method); $file = new Zend\Code\Generator\FileGenerator(); $file->setClass($class); // Render the generated file echo $file->generate(); // or write it to a file: file_put_contents('World.php', $file->generate()); ``` Both of the above samples will render the same result: ```php setName('mrMcFeeley') ->setBody('echo \'Hello, Mr. McFeeley!\';'); $class->addMethodFromGenerator($method); $file = new Zend\Code\Generator\FileGenerator(); $file->setClass($class); // Render the generated file echo $file->generate(); // Or, better yet, write it back to the original file: file_put_contents('World.php', $file->generate()); ``` The resulting class file will now look like this: ```php setDefaultValue( new Zend\Code\Generator\ValueGenerator("null") ); $parameter->setDefaultValue( new Zend\Code\Generator\ValueGenerator("['foo', 'bar']") ); ``` Internally `setDefaultValue()` also converts the values which can't be expressed in *PHP* into the value holder. ### Zend\\Code\\Generator\\PropertyGenerator `Zend\Code\Generator\PropertyGenerator` describes a class property, which may be either a constant or a variable. In each case, the property may have an optional default value associated with it. Additionally, the visibility of variable properties may be set, per the parent class, `Zend\Code\Generator\AbstractMemberGenerator`. The *API* of the class is as follows: ```php class Zend\Code\Generator\PropertyGenerator extends Zend\Code\Generator\AbstractMemberGenerator { public static function fromReflection( Zend\Code\Reflection\PropertyReflection $reflectionProperty ) public function setConst($const) public function isConst() public function setDefaultValue($defaultValue) public function getDefaultValue() public function generate() public function omitDefaultValue() } ``` php-zend-code-3.4.1/docs/book/index.md000077700000000000000000000000001357431215700213772../../README.mdustar00rootroot00000000000000php-zend-code-3.4.1/docs/book/migration.md000066400000000000000000000107341357431215700203660ustar00rootroot00000000000000# Migrating from zend-code v2 to v3 ## `string`, `int`, `float`, `bool` are no longer ignored In 2.x, a `Zend\Code\Generator\ParameterGenerator` with name `foo` and type `string`, `int`, `float` or `bool` simply generated code `"$foo"`: ```php $generator = new \Zend\Code\ParameterGenerator('foo'); $generator->setType('string'); echo $generator->generate(); // "$foo" ``` In 3.x, this code will instead produce `"string $foo"`. If you generate code that should run in PHP 5.x, it is advisable to strip `string`, `int`, `float` and `bool` from type definitions passed to `Zend\Code\ParameterGenerator` instances. The quickest way is to set the type to `null`, if it matches any of these scalar types: ```php if (in_array($type, ['string', 'int', 'float', 'bool'])) { $type = null; } $generator->setType($type); ``` ## `ParameterReflection::getType()` changes PHP 7 introduced [`ReflectionParameter#getType()`](http://php.net/manual/en/reflectionparameter.gettype.php). In order to not override this method, `Zend\Code\Reflection\ParameterReflection#getType()` was renamed to `Zend\Code\Reflection\ParameterReflection#detectType()`. If you relied on `Zend\Code\Reflection\ParameterReflection#getType()`, you can simply replace the method calls in your code. ## DocBlock types ignored by `ParameterGenerator::fromReflection()` As a direct consequence of the previous change, calls to `Zend\Code\Generator\ParameterGenerator::fromReflection()` will not mirror the type hints read from a method's DocBlock. As an example, take following code: ```php class Foo { /** * @param string $baz */ public function bar($baz) { } } $methodGenerator = \Zend\Code\Generator\MethodGenerator::fromReflection( new \Zend\Code\Reflection\MethodReflection('Foo', 'bar') ); var_dump($methodGenerator->getParameters()[0]->getType()); ``` In version 2.x, this code produces `"string"`, in version 3.x it returns `null`. If you need to rely on the types in the annotations, please use `Zend\Code\Reflection\ParameterReflection#detectType()` instead, and build a `MethodGenerator` instance manually. This change is required: since signatures in PHP 7 include scalar type hints. That also means that reflecting scalar type hints from DocBlocks into the signature of a generated method may lead to fatal errors (due to signature mismatch) at runtime. ## Type strings are validated If you attempt to generate type-hints for parameters or return types, those types are now validated before the code is generated. Be sure to check which values you pass to `Zend\Code\Generator\MethodGenerator#setReturnType()` or `Zend\Code\Generator\ParameterGenerator#setType()`, as you may incur in a `Zend\Code\Generator\Exception\InvalidArgumentException` being thrown if any of those types are invalid strings: ```php $parameterGenerator->setType('foo'); // valid $parameterGenerator->setType('array'); // valid $parameterGenerator->setType('bool'); // valid $parameterGenerator->setType('123'); // invalid (throws exception) $parameterGenerator->setType(''); // invalid (throws exception) $parameterGenerator->setType('*'); // invalid (throws exception) $parameterGenerator->setType('\\'); // invalid (throws exception) ``` ## Generated type-hints are now prefixed by `"\"` Generated type-hints are now prefixed with the `NAMESPACE_SEPARATOR`, `"\"`. Take following example code: ```php $parameter = new \Zend\Code\Generator\ParameterGenerator('bar', 'baz'); $method = new \Zend\Code\Generator\MethodGenerator('foo', [$parameter]); $method->setReturnType('tab'); echo $method->generate(); ``` This code produces `public function foo(baz $bar) {}` in 2.x. In version 3.x, it produces `public function foo(\baz $bar) : \tab {}`. In order to avoid migration problems, be sure to always pass fully qualified class names to `Zend\Code\Generator\MethodGenerator` and `Zend\Code\Generator\ParameterGenerator`. ## `ParameterGenerator::$simple` was removed If you extended `Zend\Code\Generator\ParameterGenerator`, be sure to check if you are accessing the protected static variable `$simple`: it was removed, and you should adapt your code by either copying it into your class or avoiding its usage. ## `ParameterGenerator::$type` has changed If you extended `Zend\Code\Generator\ParameterGenerator`, be sure to check if you are accessing the protected variable `$type`: its type has changed. While it can still be used as a string via an explicit `(string)` cast, the type of this protected member is now `null|Zend\Code\Generator\TypeGenerator`. php-zend-code-3.4.1/mkdocs.yml000066400000000000000000000006551357431215700161750ustar00rootroot00000000000000docs_dir: docs/book site_dir: docs/html pages: - Home: index.md - "Code Generation": - Introduction: generator/intro.md - Examples: generator/examples.md - Reference: generator/reference.md - Migration: migration.md site_name: zend-code site_description: 'Extensions to the PHP Reflection API, static code scanning, and code generation' repo_url: 'https://github.com/zendframework/zend-code' php-zend-code-3.4.1/phpcs.xml000066400000000000000000000005121357431215700160210ustar00rootroot00000000000000 src test */TestAsset/* */_files/* php-zend-code-3.4.1/phpunit.xml.dist000066400000000000000000000014221357431215700173360ustar00rootroot00000000000000 ./test ./src php-zend-code-3.4.1/src/000077500000000000000000000000001357431215700147535ustar00rootroot00000000000000php-zend-code-3.4.1/src/Annotation/000077500000000000000000000000001357431215700170655ustar00rootroot00000000000000php-zend-code-3.4.1/src/Annotation/AnnotationCollection.php000066400000000000000000000014301357431215700237220ustar00rootroot00000000000000setIdentifiers([ __CLASS__, get_class($this), ]); $this->events = $events; return $this; } /** * Retrieve event manager * * Lazy loads an instance if none registered. * * @return EventManagerInterface */ public function getEventManager() { if (null === $this->events) { $this->setEventManager(new EventManager()); } return $this->events; } /** * Attach a parser to listen to the createAnnotation event * * @param ParserInterface $parser * @return AnnotationManager */ public function attach(ParserInterface $parser) { $this->getEventManager() ->attach(self::EVENT_CREATE_ANNOTATION, [$parser, 'onCreateAnnotation']); return $this; } /** * Create Annotation * * @param string[] $annotationData * @return false|\stdClass */ public function createAnnotation(array $annotationData) { $event = new Event(); $event->setName(self::EVENT_CREATE_ANNOTATION); $event->setTarget($this); $event->setParams([ 'class' => $annotationData[0], 'content' => $annotationData[1], 'raw' => $annotationData[2], ]); $eventManager = $this->getEventManager(); $results = $eventManager->triggerEventUntil(function ($r) { return is_object($r); }, $event); $annotation = $results->last(); return is_object($annotation) ? $annotation : false; } } php-zend-code-3.4.1/src/Annotation/Parser/000077500000000000000000000000001357431215700203215ustar00rootroot00000000000000php-zend-code-3.4.1/src/Annotation/Parser/DoctrineAnnotationParser.php000066400000000000000000000107631357431215700260200ustar00rootroot00000000000000docParser = $docParser; return $this; } /** * Retrieve the DocParser instance * * If none is registered, lazy-loads a new instance. * * @return DocParser */ public function getDocParser() { if (! $this->docParser instanceof DocParser) { $this->setDocParser(new DocParser()); } return $this->docParser; } /** * Handle annotation creation * * @param EventInterface $e * @return false|\stdClass */ public function onCreateAnnotation(EventInterface $e) { $annotationClass = $e->getParam('class', false); if (! $annotationClass) { return false; } if (! isset($this->allowedAnnotations[$annotationClass])) { return false; } $annotationString = $e->getParam('raw', false); if (! $annotationString) { return false; } // Annotation classes provided by the AnnotationScanner are already // resolved to fully-qualified class names. Adding the global namespace // prefix allows the Doctrine annotation parser to locate the annotation // class correctly. $annotationString = preg_replace('/^(@)/', '$1\\', $annotationString); $parser = $this->getDocParser(); $annotations = $parser->parse($annotationString); if (empty($annotations)) { return false; } $annotation = array_shift($annotations); if (! is_object($annotation)) { return false; } return $annotation; } /** * Specify an allowed annotation class * * @param string $annotation * @return DoctrineAnnotationParser */ public function registerAnnotation($annotation) { $this->allowedAnnotations[$annotation] = true; return $this; } /** * Set many allowed annotations at once * * @param array|Traversable $annotations Array or traversable object of * annotation class names * @throws Exception\InvalidArgumentException * @return DoctrineAnnotationParser */ public function registerAnnotations($annotations) { if (! is_array($annotations) && ! $annotations instanceof Traversable) { throw new Exception\InvalidArgumentException(sprintf( '%s: expects an array or Traversable; received "%s"', __METHOD__, is_object($annotations) ? get_class($annotations) : gettype($annotations) )); } foreach ($annotations as $annotation) { $this->allowedAnnotations[$annotation] = true; } return $this; } } php-zend-code-3.4.1/src/Annotation/Parser/GenericAnnotationParser.php000066400000000000000000000145711357431215700256260ustar00rootroot00000000000000getParam('class', false); if (! $class || ! $this->hasAnnotation($class)) { return false; } $content = $e->getParam('content', ''); $content = trim($content, '()'); if ($this->hasAlias($class)) { $class = $this->resolveAlias($class); } $index = array_search($class, $this->annotationNames); $annotation = $this->annotations[$index]; $newAnnotation = clone $annotation; if ($content) { $newAnnotation->initialize($content); } return $newAnnotation; } /** * Register annotations * * @param string|AnnotationInterface $annotation String class name of an * AnnotationInterface implementation, or actual instance * @return void * @throws Exception\InvalidArgumentException */ public function registerAnnotation($annotation) { $class = false; if (is_string($annotation) && class_exists($annotation)) { $class = $annotation; $annotation = new $annotation(); } if (! $annotation instanceof AnnotationInterface) { throw new Exception\InvalidArgumentException(sprintf( '%s: expects an instance of %s\AnnotationInterface; received "%s"', __METHOD__, __NAMESPACE__, is_object($annotation) ? get_class($annotation) : gettype($annotation) )); } $class = $class ?: get_class($annotation); if (in_array($class, $this->annotationNames)) { throw new Exception\InvalidArgumentException(sprintf( 'An annotation for this class %s already exists', $class )); } $this->annotations[] = $annotation; $this->annotationNames[] = $class; } /** * Register many annotations at once * * @param array|Traversable $annotations * @throws Exception\InvalidArgumentException * @return GenericAnnotationParser */ public function registerAnnotations($annotations) { if (! is_array($annotations) && ! $annotations instanceof Traversable) { throw new Exception\InvalidArgumentException(sprintf( '%s: expects an array or Traversable; received "%s"', __METHOD__, is_object($annotations) ? get_class($annotations) : gettype($annotations) )); } foreach ($annotations as $annotation) { $this->registerAnnotation($annotation); } return $this; } /** * Checks if the manager has annotations for a class * * @param string $class * @return bool */ public function hasAnnotation($class) { if (in_array($class, $this->annotationNames)) { return true; } if ($this->hasAlias($class)) { return true; } return false; } /** * Alias an annotation name * * @param string $alias * @param string $class May be either a registered annotation name or another alias * @throws Exception\InvalidArgumentException * @return GenericAnnotationParser */ public function setAlias($alias, $class) { if (! in_array($class, $this->annotationNames) && ! $this->hasAlias($class)) { throw new Exception\InvalidArgumentException(sprintf( '%s: Cannot alias "%s" to "%s", as class "%s" is not currently a registered annotation or alias', __METHOD__, $alias, $class, $class )); } $alias = $this->normalizeAlias($alias); $this->aliases[$alias] = $class; return $this; } /** * Normalize an alias name * * @param string $alias * @return string */ protected function normalizeAlias($alias) { return strtolower(str_replace(['-', '_', ' ', '\\', '/'], '', $alias)); } /** * Do we have an alias by the provided name? * * @param string $alias * @return bool */ protected function hasAlias($alias) { $alias = $this->normalizeAlias($alias); return isset($this->aliases[$alias]); } /** * Resolve an alias to a class name * * @param string $alias * @return string */ protected function resolveAlias($alias) { do { $normalized = $this->normalizeAlias($alias); $class = $this->aliases[$normalized]; } while ($this->hasAlias($class)); return $class; } } php-zend-code-3.4.1/src/Annotation/Parser/ParserInterface.php000066400000000000000000000017541357431215700241160ustar00rootroot00000000000000 'integer', self::STRICT_TYPES => 'integer', self::ENCODING => 'string', ]; /** * @var string */ protected $directive; /** * @var int|string */ protected $value; private function __construct(string $directive, $value) { $this->directive = $directive; $this->value = $value; } /** * @return string */ public function getDirective(): string { return $this->directive; } /** * @return int|string */ public function getValue() { return $this->value; } /** * @param int $value * @return self */ public static function ticks(int $value): self { return new self(self::TICKS, $value); } /** * @param int $value * @return self */ public static function strictTypes(int $value): self { return new self(self::STRICT_TYPES, $value); } /** * @param string $value * @return self */ public static function encoding(string $value): self { return new self(self::ENCODING, $value); } public static function fromArray(array $config): self { $directive = key($config); $value = $config[$directive]; if (! isset(self::ALLOWED[$directive])) { throw new InvalidArgumentException( sprintf( 'Declare directive must be one of: %s.', implode(', ', array_keys(self::ALLOWED)) ) ); } if (gettype($value) !== self::ALLOWED[$directive]) { throw new InvalidArgumentException( sprintf( 'Declare value invalid. Expected %s, got %s.', self::ALLOWED[$directive], gettype($value) ) ); } $method = str_replace('_', '', lcfirst(ucwords($directive, '_'))); return self::{$method}($value); } /** * @return string */ public function getStatement(): string { $value = is_string($this->value) ? '\'' . $this->value . '\'' : $this->value; return sprintf('declare(%s=%s);', $this->directive, $value); } } php-zend-code-3.4.1/src/Exception/000077500000000000000000000000001357431215700167115ustar00rootroot00000000000000php-zend-code-3.4.1/src/Exception/BadMethodCallException.php000066400000000000000000000006711357431215700237300ustar00rootroot00000000000000setOptions($options); } } /** * @param bool $isSourceDirty * @return AbstractGenerator */ public function setSourceDirty($isSourceDirty = true) { $this->isSourceDirty = (bool) $isSourceDirty; return $this; } /** * @return bool */ public function isSourceDirty() { return $this->isSourceDirty; } /** * @param string $indentation * @return AbstractGenerator */ public function setIndentation($indentation) { $this->indentation = (string) $indentation; return $this; } /** * @return string */ public function getIndentation() { return $this->indentation; } /** * @param string $sourceContent * @return AbstractGenerator */ public function setSourceContent($sourceContent) { $this->sourceContent = (string) $sourceContent; return $this; } /** * @return string */ public function getSourceContent() { return $this->sourceContent; } /** * @param array|Traversable $options * @throws Exception\InvalidArgumentException * @return AbstractGenerator */ public function setOptions($options) { if (! is_array($options) && ! $options instanceof Traversable) { throw new Exception\InvalidArgumentException(sprintf( '%s expects an array or Traversable object; received "%s"', __METHOD__, is_object($options) ? get_class($options) : gettype($options) )); } foreach ($options as $optionName => $optionValue) { $methodName = 'set' . $optionName; if (method_exists($this, $methodName)) { $this->{$methodName}($optionValue); } } return $this; } } php-zend-code-3.4.1/src/Generator/AbstractMemberGenerator.php000066400000000000000000000136261357431215700241640ustar00rootroot00000000000000flags = $flags; return $this; } /** * @param int $flag * @return AbstractMemberGenerator */ public function addFlag($flag) { $this->setFlags($this->flags | $flag); return $this; } /** * @param int $flag * @return AbstractMemberGenerator */ public function removeFlag($flag) { $this->setFlags($this->flags & ~$flag); return $this; } /** * @param bool $isAbstract * @return AbstractMemberGenerator */ public function setAbstract($isAbstract) { return $isAbstract ? $this->addFlag(self::FLAG_ABSTRACT) : $this->removeFlag(self::FLAG_ABSTRACT); } /** * @return bool */ public function isAbstract() { return (bool) ($this->flags & self::FLAG_ABSTRACT); } /** * @param bool $isInterface * @return AbstractMemberGenerator */ public function setInterface($isInterface) { return $isInterface ? $this->addFlag(self::FLAG_INTERFACE) : $this->removeFlag(self::FLAG_INTERFACE); } /** * @return bool */ public function isInterface() { return (bool) ($this->flags & self::FLAG_INTERFACE); } /** * @param bool $isFinal * @return AbstractMemberGenerator */ public function setFinal($isFinal) { return $isFinal ? $this->addFlag(self::FLAG_FINAL) : $this->removeFlag(self::FLAG_FINAL); } /** * @return bool */ public function isFinal() { return (bool) ($this->flags & self::FLAG_FINAL); } /** * @param bool $isStatic * @return AbstractMemberGenerator */ public function setStatic($isStatic) { return $isStatic ? $this->addFlag(self::FLAG_STATIC) : $this->removeFlag(self::FLAG_STATIC); } /** * @return bool */ public function isStatic() { return (bool) ($this->flags & self::FLAG_STATIC); // is FLAG_STATIC in flags } /** * @param string $visibility * @return AbstractMemberGenerator */ public function setVisibility($visibility) { switch ($visibility) { case self::VISIBILITY_PUBLIC: $this->removeFlag(self::FLAG_PRIVATE | self::FLAG_PROTECTED); // remove both $this->addFlag(self::FLAG_PUBLIC); break; case self::VISIBILITY_PROTECTED: $this->removeFlag(self::FLAG_PUBLIC | self::FLAG_PRIVATE); // remove both $this->addFlag(self::FLAG_PROTECTED); break; case self::VISIBILITY_PRIVATE: $this->removeFlag(self::FLAG_PUBLIC | self::FLAG_PROTECTED); // remove both $this->addFlag(self::FLAG_PRIVATE); break; } return $this; } /** * @return string */ public function getVisibility() { switch (true) { case $this->flags & self::FLAG_PROTECTED: return self::VISIBILITY_PROTECTED; case $this->flags & self::FLAG_PRIVATE: return self::VISIBILITY_PRIVATE; default: return self::VISIBILITY_PUBLIC; } } /** * @param string $name * @return AbstractMemberGenerator */ public function setName($name) { $this->name = (string) $name; return $this; } /** * @return string */ public function getName() { return $this->name; } /** * @param DocBlockGenerator|string $docBlock * @throws Exception\InvalidArgumentException * @return AbstractMemberGenerator */ public function setDocBlock($docBlock) { if (is_string($docBlock)) { $docBlock = new DocBlockGenerator($docBlock); } elseif (! $docBlock instanceof DocBlockGenerator) { throw new Exception\InvalidArgumentException(sprintf( '%s is expecting either a string, array or an instance of %s\DocBlockGenerator', __METHOD__, __NAMESPACE__ )); } $this->docBlock = $docBlock; return $this; } public function removeDocBlock(): void { $this->docBlock = null; } /** * @return DocBlockGenerator|null */ public function getDocBlock() { return $this->docBlock; } } php-zend-code-3.4.1/src/Generator/BodyGenerator.php000066400000000000000000000015601357431215700221600ustar00rootroot00000000000000content = (string) $content; return $this; } /** * @return string */ public function getContent() { return $this->content; } /** * @return string */ public function generate() { return $this->getContent(); } } php-zend-code-3.4.1/src/Generator/ClassGenerator.php000066400000000000000000000717251357431215700223420ustar00rootroot00000000000000getName()); $cg->setSourceContent($cg->getSourceContent()); $cg->setSourceDirty(false); if ($classReflection->getDocComment() != '') { $cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock())); } $cg->setAbstract($classReflection->isAbstract()); // set the namespace if ($classReflection->inNamespace()) { $cg->setNamespaceName($classReflection->getNamespaceName()); } /* @var \Zend\Code\Reflection\ClassReflection $parentClass */ $parentClass = $classReflection->getParentClass(); $interfaces = $classReflection->getInterfaces(); if ($parentClass) { $cg->setExtendedClass($parentClass->getName()); $interfaces = array_diff($interfaces, $parentClass->getInterfaces()); } $interfaceNames = []; foreach ($interfaces as $interface) { /* @var \Zend\Code\Reflection\ClassReflection $interface */ $interfaceNames[] = $interface->getName(); } $cg->setImplementedInterfaces($interfaceNames); $properties = []; foreach ($classReflection->getProperties() as $reflectionProperty) { if ($reflectionProperty->getDeclaringClass()->getName() == $classReflection->getName()) { $properties[] = PropertyGenerator::fromReflection($reflectionProperty); } } $cg->addProperties($properties); $constants = []; foreach ($classReflection->getConstants() as $name => $value) { $constants[] = [ 'name' => $name, 'value' => $value, ]; } $cg->addConstants($constants); $methods = []; foreach ($classReflection->getMethods() as $reflectionMethod) { $className = $cg->getNamespaceName() ? $cg->getNamespaceName() . '\\' . $cg->getName() : $cg->getName(); if ($reflectionMethod->getDeclaringClass()->getName() == $className) { $methods[] = MethodGenerator::fromReflection($reflectionMethod); } } $cg->addMethods($methods); return $cg; } /** * Generate from array * * @configkey name string [required] Class Name * @configkey filegenerator FileGenerator File generator that holds this class * @configkey namespacename string The namespace for this class * @configkey docblock string The docblock information * @configkey flags int Flags, one of ClassGenerator::FLAG_ABSTRACT ClassGenerator::FLAG_FINAL * @configkey extendedclass string Class which this class is extending * @configkey implementedinterfaces * @configkey properties * @configkey methods * * @throws Exception\InvalidArgumentException * @param array $array * @return self */ public static function fromArray(array $array) { if (! isset($array['name'])) { throw new Exception\InvalidArgumentException( 'Class generator requires that a name is provided for this object' ); } $cg = new static($array['name']); foreach ($array as $name => $value) { // normalize key switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { case 'containingfile': $cg->setContainingFileGenerator($value); break; case 'namespacename': $cg->setNamespaceName($value); break; case 'docblock': $docBlock = $value instanceof DocBlockGenerator ? $value : DocBlockGenerator::fromArray($value); $cg->setDocBlock($docBlock); break; case 'flags': $cg->setFlags($value); break; case 'extendedclass': $cg->setExtendedClass($value); break; case 'implementedinterfaces': $cg->setImplementedInterfaces($value); break; case 'properties': $cg->addProperties($value); break; case 'methods': $cg->addMethods($value); break; } } return $cg; } /** * @param string $name * @param string $namespaceName * @param array|string $flags * @param string $extends * @param array $interfaces * @param array $properties * @param array $methods * @param DocBlockGenerator $docBlock */ public function __construct( $name = null, $namespaceName = null, $flags = null, $extends = null, $interfaces = [], $properties = [], $methods = [], $docBlock = null ) { $this->traitUsageGenerator = new TraitUsageGenerator($this); if ($name !== null) { $this->setName($name); } if ($namespaceName !== null) { $this->setNamespaceName($namespaceName); } if ($flags !== null) { $this->setFlags($flags); } if ($properties !== []) { $this->addProperties($properties); } if ($extends !== null) { $this->setExtendedClass($extends); } if (is_array($interfaces)) { $this->setImplementedInterfaces($interfaces); } if ($methods !== []) { $this->addMethods($methods); } if ($docBlock !== null) { $this->setDocBlock($docBlock); } } /** * @param string $name * @return self */ public function setName($name) { if (false !== strpos($name, '\\')) { $namespace = substr($name, 0, strrpos($name, '\\')); $name = substr($name, strrpos($name, '\\') + 1); $this->setNamespaceName($namespace); } $this->name = $name; return $this; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $namespaceName * @return self */ public function setNamespaceName($namespaceName) { $this->namespaceName = $namespaceName; return $this; } /** * @return string */ public function getNamespaceName() { return $this->namespaceName; } /** * @param FileGenerator $fileGenerator * @return self */ public function setContainingFileGenerator(FileGenerator $fileGenerator) { $this->containingFileGenerator = $fileGenerator; return $this; } /** * @return FileGenerator */ public function getContainingFileGenerator() { return $this->containingFileGenerator; } /** * @param DocBlockGenerator $docBlock * @return self */ public function setDocBlock(DocBlockGenerator $docBlock) { $this->docBlock = $docBlock; return $this; } /** * @return DocBlockGenerator */ public function getDocBlock() { return $this->docBlock; } /** * @param array|string $flags * @return self */ public function setFlags($flags) { if (is_array($flags)) { $flagsArray = $flags; $flags = 0x00; foreach ($flagsArray as $flag) { $flags |= $flag; } } // check that visibility is one of three $this->flags = $flags; return $this; } /** * @param string $flag * @return self */ public function addFlag($flag) { $this->setFlags($this->flags | $flag); return $this; } /** * @param string $flag * @return self */ public function removeFlag($flag) { $this->setFlags($this->flags & ~$flag); return $this; } /** * @param bool $isAbstract * @return self */ public function setAbstract($isAbstract) { return $isAbstract ? $this->addFlag(self::FLAG_ABSTRACT) : $this->removeFlag(self::FLAG_ABSTRACT); } /** * @return bool */ public function isAbstract() { return (bool) ($this->flags & self::FLAG_ABSTRACT); } /** * @param bool $isFinal * @return self */ public function setFinal($isFinal) { return $isFinal ? $this->addFlag(self::FLAG_FINAL) : $this->removeFlag(self::FLAG_FINAL); } /** * @return bool */ public function isFinal() { return $this->flags & self::FLAG_FINAL; } /** * @param string $extendedClass * @return self */ public function setExtendedClass($extendedClass) { $this->extendedClass = $extendedClass; return $this; } /** * @return string */ public function getExtendedClass() { return $this->extendedClass; } /** * @return bool */ public function hasExtentedClass() { return ! empty($this->extendedClass); } /** * @return self */ public function removeExtentedClass() { $this->setExtendedClass(null); return $this; } /** * @param array $implementedInterfaces * @return self */ public function setImplementedInterfaces(array $implementedInterfaces) { array_map(function ($implementedInterface) { return (string) TypeGenerator::fromTypeString($implementedInterface); }, $implementedInterfaces); $this->implementedInterfaces = $implementedInterfaces; return $this; } /** * @return array */ public function getImplementedInterfaces() { return $this->implementedInterfaces; } /** * @param string $implementedInterface * @return bool */ public function hasImplementedInterface($implementedInterface) { $implementedInterface = (string) TypeGenerator::fromTypeString($implementedInterface); return in_array($implementedInterface, $this->implementedInterfaces); } /** * @param string $implementedInterface * @return self */ public function removeImplementedInterface($implementedInterface) { $implementedInterface = (string) TypeGenerator::fromTypeString($implementedInterface); unset($this->implementedInterfaces[array_search($implementedInterface, $this->implementedInterfaces)]); return $this; } /** * @param string $constantName * @return PropertyGenerator|false */ public function getConstant($constantName) { if (isset($this->constants[$constantName])) { return $this->constants[$constantName]; } return false; } /** * @return PropertyGenerator[] indexed by constant name */ public function getConstants() { return $this->constants; } /** * @param string $constantName * @return self */ public function removeConstant($constantName) { unset($this->constants[$constantName]); return $this; } /** * @param string $constantName * @return bool */ public function hasConstant($constantName) { return isset($this->constants[$constantName]); } /** * Add constant from PropertyGenerator * * @param PropertyGenerator $constant * @throws Exception\InvalidArgumentException * @return self */ public function addConstantFromGenerator(PropertyGenerator $constant) { $constantName = $constant->getName(); if (isset($this->constants[$constantName])) { throw new Exception\InvalidArgumentException(sprintf( 'A constant by name %s already exists in this class.', $constantName )); } if (! $constant->isConst()) { throw new Exception\InvalidArgumentException(sprintf( 'The value %s is not defined as a constant.', $constantName )); } $this->constants[$constantName] = $constant; return $this; } /** * Add Constant * * @param string $name Non-empty string * @param string|int|null|float|array $value Scalar * * @throws Exception\InvalidArgumentException * * @return self */ public function addConstant($name, $value) { if (empty($name) || ! is_string($name)) { throw new Exception\InvalidArgumentException(sprintf( '%s expects string for name', __METHOD__ )); } $this->validateConstantValue($value); return $this->addConstantFromGenerator( new PropertyGenerator($name, new PropertyValueGenerator($value), PropertyGenerator::FLAG_CONSTANT) ); } /** * @param PropertyGenerator[]|array[] $constants * * @return self */ public function addConstants(array $constants) { foreach ($constants as $constant) { if ($constant instanceof PropertyGenerator) { $this->addPropertyFromGenerator($constant); } else { if (is_array($constant)) { $this->addConstant(...array_values($constant)); } } } return $this; } /** * @param array $properties * @return self */ public function addProperties(array $properties) { foreach ($properties as $property) { if ($property instanceof PropertyGenerator) { $this->addPropertyFromGenerator($property); } else { if (is_string($property)) { $this->addProperty($property); } elseif (is_array($property)) { $this->addProperty(...array_values($property)); } } } return $this; } /** * Add Property from scalars * * @param string $name * @param string|array $defaultValue * @param int $flags * @throws Exception\InvalidArgumentException * @return self */ public function addProperty($name, $defaultValue = null, $flags = PropertyGenerator::FLAG_PUBLIC) { if (! is_string($name)) { throw new Exception\InvalidArgumentException(sprintf( '%s::%s expects string for name', get_class($this), __FUNCTION__ )); } // backwards compatibility // @todo remove this on next major version if ($flags === PropertyGenerator::FLAG_CONSTANT) { return $this->addConstant($name, $defaultValue); } return $this->addPropertyFromGenerator(new PropertyGenerator($name, $defaultValue, $flags)); } /** * Add property from PropertyGenerator * * @param PropertyGenerator $property * @throws Exception\InvalidArgumentException * @return self */ public function addPropertyFromGenerator(PropertyGenerator $property) { $propertyName = $property->getName(); if (isset($this->properties[$propertyName])) { throw new Exception\InvalidArgumentException(sprintf( 'A property by name %s already exists in this class.', $propertyName )); } // backwards compatibility // @todo remove this on next major version if ($property->isConst()) { return $this->addConstantFromGenerator($property); } $this->properties[$propertyName] = $property; return $this; } /** * @return PropertyGenerator[] */ public function getProperties() { return $this->properties; } /** * @param string $propertyName * @return PropertyGenerator|false */ public function getProperty($propertyName) { foreach ($this->getProperties() as $property) { if ($property->getName() == $propertyName) { return $property; } } return false; } /** * Add a class to "use" classes * * @param string $use * @param string|null $useAlias * @return self */ public function addUse($use, $useAlias = null) { $this->traitUsageGenerator->addUse($use, $useAlias); return $this; } /** * @param string $use * @return bool */ public function hasUse($use) { return $this->traitUsageGenerator->hasUse($use); } /** * @param string $use * @return self */ public function removeUse($use) { $this->traitUsageGenerator->removeUse($use); return $this; } /** * @param string $use * @return bool */ public function hasUseAlias($use) { return $this->traitUsageGenerator->hasUseAlias($use); } /** * @param string $use * @return self */ public function removeUseAlias($use) { $this->traitUsageGenerator->removeUseAlias($use); return $this; } /** * Returns the "use" classes * * @return array */ public function getUses() { return $this->traitUsageGenerator->getUses(); } /** * @param string $propertyName * @return self */ public function removeProperty($propertyName) { unset($this->properties[$propertyName]); return $this; } /** * @param string $propertyName * @return bool */ public function hasProperty($propertyName) { return isset($this->properties[$propertyName]); } /** * @param array $methods * @return self */ public function addMethods(array $methods) { foreach ($methods as $method) { if ($method instanceof MethodGenerator) { $this->addMethodFromGenerator($method); } else { if (is_string($method)) { $this->addMethod($method); } elseif (is_array($method)) { $this->addMethod(...array_values($method)); } } } return $this; } /** * Add Method from scalars * * @param string $name * @param array $parameters * @param int $flags * @param string $body * @param string $docBlock * @throws Exception\InvalidArgumentException * @return self */ public function addMethod( $name, array $parameters = [], $flags = MethodGenerator::FLAG_PUBLIC, $body = null, $docBlock = null ) { if (! is_string($name)) { throw new Exception\InvalidArgumentException(sprintf( '%s::%s expects string for name', get_class($this), __FUNCTION__ )); } return $this->addMethodFromGenerator(new MethodGenerator($name, $parameters, $flags, $body, $docBlock)); } /** * Add Method from MethodGenerator * * @param MethodGenerator $method * @throws Exception\InvalidArgumentException * @return self */ public function addMethodFromGenerator(MethodGenerator $method) { $methodName = $method->getName(); if ($this->hasMethod($methodName)) { throw new Exception\InvalidArgumentException(sprintf( 'A method by name %s already exists in this class.', $methodName )); } $this->methods[strtolower($methodName)] = $method; return $this; } /** * @return MethodGenerator[] */ public function getMethods() { return $this->methods; } /** * @param string $methodName * @return MethodGenerator|false */ public function getMethod($methodName) { return $this->hasMethod($methodName) ? $this->methods[strtolower($methodName)] : false; } /** * @param string $methodName * @return self */ public function removeMethod($methodName) { unset($this->methods[strtolower($methodName)]); return $this; } /** * @param string $methodName * @return bool */ public function hasMethod($methodName) { return isset($this->methods[strtolower($methodName)]); } /** * @inheritDoc */ public function addTrait($trait) { $this->traitUsageGenerator->addTrait($trait); return $this; } /** * @inheritDoc */ public function addTraits(array $traits) { $this->traitUsageGenerator->addTraits($traits); return $this; } /** * @inheritDoc */ public function hasTrait($traitName) { return $this->traitUsageGenerator->hasTrait($traitName); } /** * @inheritDoc */ public function getTraits() { return $this->traitUsageGenerator->getTraits(); } /** * @inheritDoc */ public function removeTrait($traitName) { return $this->traitUsageGenerator->removeTrait($traitName); } /** * @inheritDoc */ public function addTraitAlias($method, $alias, $visibility = null) { $this->traitUsageGenerator->addTraitAlias($method, $alias, $visibility); return $this; } /** * @inheritDoc */ public function getTraitAliases() { return $this->traitUsageGenerator->getTraitAliases(); } /** * @inheritDoc */ public function addTraitOverride($method, $traitsToReplace) { $this->traitUsageGenerator->addTraitOverride($method, $traitsToReplace); return $this; } /** * @inheritDoc */ public function removeTraitOverride($method, $overridesToRemove = null) { $this->traitUsageGenerator->removeTraitOverride($method, $overridesToRemove); return $this; } /** * @inheritDoc */ public function getTraitOverrides() { return $this->traitUsageGenerator->getTraitOverrides(); } /** * @return bool */ public function isSourceDirty() { if (($docBlock = $this->getDocBlock()) && $docBlock->isSourceDirty()) { return true; } foreach ($this->getProperties() as $property) { if ($property->isSourceDirty()) { return true; } } foreach ($this->getMethods() as $method) { if ($method->isSourceDirty()) { return true; } } return parent::isSourceDirty(); } /** * @inheritDoc */ public function generate() { if (! $this->isSourceDirty()) { $output = $this->getSourceContent(); if (! empty($output)) { return $output; } } $indent = $this->getIndentation(); $output = ''; if (null !== ($namespace = $this->getNamespaceName())) { $output .= 'namespace ' . $namespace . ';' . self::LINE_FEED . self::LINE_FEED; } $uses = $this->getUses(); if (! empty($uses)) { foreach ($uses as $use) { $output .= 'use ' . $use . ';' . self::LINE_FEED; } $output .= self::LINE_FEED; } if (null !== ($docBlock = $this->getDocBlock())) { $docBlock->setIndentation(''); $output .= $docBlock->generate(); } if ($this->isAbstract()) { $output .= 'abstract '; } elseif ($this->isFinal()) { $output .= 'final '; } $output .= static::OBJECT_TYPE . ' ' . $this->getName(); if (! empty($this->extendedClass)) { $output .= ' extends ' . $this->generateShortOrCompleteClassname($this->extendedClass); } $implemented = $this->getImplementedInterfaces(); if (! empty($implemented)) { $implemented = array_map([$this, 'generateShortOrCompleteClassname'], $implemented); $output .= ' ' . static::IMPLEMENTS_KEYWORD . ' ' . implode(', ', $implemented); } $output .= self::LINE_FEED . '{' . self::LINE_FEED . self::LINE_FEED; $output .= $this->traitUsageGenerator->generate(); $constants = $this->getConstants(); foreach ($constants as $constant) { $output .= $constant->generate() . self::LINE_FEED . self::LINE_FEED; } $properties = $this->getProperties(); foreach ($properties as $property) { $output .= $property->generate() . self::LINE_FEED . self::LINE_FEED; } $methods = $this->getMethods(); foreach ($methods as $method) { $output .= $method->generate() . self::LINE_FEED; } $output .= self::LINE_FEED . '}' . self::LINE_FEED; return $output; } /** * @param mixed $value * * @return void * * @throws Exception\InvalidArgumentException */ private function validateConstantValue($value) { if (null === $value || is_scalar($value)) { return; } if (is_array($value)) { array_walk($value, [$this, 'validateConstantValue']); return; } throw new Exception\InvalidArgumentException(sprintf( 'Expected value for constant, value must be a "scalar" or "null", "%s" found', gettype($value) )); } /** * @param string $fqnClassName * * @return string */ private function generateShortOrCompleteClassname($fqnClassName) { $fqnClassName = ltrim($fqnClassName, '\\'); $parts = explode('\\', $fqnClassName); $className = array_pop($parts); $classNamespace = implode('\\', $parts); $currentNamespace = (string) $this->getNamespaceName(); if ($this->hasUseAlias($fqnClassName)) { return $this->traitUsageGenerator->getUseAlias($fqnClassName); } if ($this->hasUseAlias($classNamespace)) { $namespaceAlias = $this->traitUsageGenerator->getUseAlias($classNamespace); return $namespaceAlias . '\\' . $className; } if ($this->traitUsageGenerator->isUseAlias($fqnClassName)) { return $fqnClassName; } if ($this->traitUsageGenerator->isUseAlias($classNamespace)) { return $fqnClassName; } if ($classNamespace === $currentNamespace || in_array($fqnClassName, $this->getUses())) { return $className; } return '\\' . $fqnClassName; } } php-zend-code-3.4.1/src/Generator/DocBlock/000077500000000000000000000000001357431215700203615ustar00rootroot00000000000000php-zend-code-3.4.1/src/Generator/DocBlock/Tag.php000066400000000000000000000026571357431215700216170ustar00rootroot00000000000000initializeDefaultTags(); return $tagManager->createTagFromReflection($reflectionTag); } /** * @param string $description * @return Tag * @deprecated Deprecated in 2.3. Use GenericTag::setContent() instead */ public function setDescription($description) { return $this->setContent($description); } /** * @return string * @deprecated Deprecated in 2.3. Use GenericTag::getContent() instead */ public function getDescription() { return $this->getContent(); } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/000077500000000000000000000000001357431215700210745ustar00rootroot00000000000000php-zend-code-3.4.1/src/Generator/DocBlock/Tag/AbstractTypeableTag.php000066400000000000000000000042471357431215700255010ustar00rootroot00000000000000setTypes($types); } if (! empty($description)) { $this->setDescription($description); } } /** * @param string $description * @return AbstractTypeableTag */ public function setDescription($description) { $this->description = $description; return $this; } /** * @return string */ public function getDescription() { return $this->description; } /** * Array of types or string with types delimited by pipe (|) * e.g. array('int', 'null') or "int|null" * * @param array|string $types * @return AbstractTypeableTag */ public function setTypes($types) { if (is_string($types)) { $types = explode('|', $types); } $this->types = $types; return $this; } /** * @return array */ public function getTypes() { return $this->types; } /** * @param string $delimiter * @return string */ public function getTypesAsString($delimiter = '|') { return implode($delimiter, $this->types); } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/AuthorTag.php000066400000000000000000000047651357431215700235170ustar00rootroot00000000000000setAuthorName($authorName); } if (! empty($authorEmail)) { $this->setAuthorEmail($authorEmail); } } /** * @param ReflectionTagInterface $reflectionTag * @return AuthorTag * @deprecated Deprecated in 2.3. Use TagManager::createTagFromReflection() instead */ public static function fromReflection(ReflectionTagInterface $reflectionTag) { $tagManager = new TagManager(); $tagManager->initializeDefaultTags(); return $tagManager->createTagFromReflection($reflectionTag); } /** * @return string */ public function getName() { return 'author'; } /** * @param string $authorEmail * @return AuthorTag */ public function setAuthorEmail($authorEmail) { $this->authorEmail = $authorEmail; return $this; } /** * @return string */ public function getAuthorEmail() { return $this->authorEmail; } /** * @param string $authorName * @return AuthorTag */ public function setAuthorName($authorName) { $this->authorName = $authorName; return $this; } /** * @return string */ public function getAuthorName() { return $this->authorName; } /** * @return string */ public function generate() { $output = '@author' . (! empty($this->authorName) ? ' ' . $this->authorName : '') . (! empty($this->authorEmail) ? ' <' . $this->authorEmail . '>' : ''); return $output; } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/GenericTag.php000066400000000000000000000034121357431215700236150ustar00rootroot00000000000000setName($name); } if (! empty($content)) { $this->setContent($content); } } /** * @param string $name * @return GenericTag */ public function setName($name) { $this->name = ltrim($name, '@'); return $this; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $content * @return GenericTag */ public function setContent($content) { $this->content = $content; return $this; } /** * @return string */ public function getContent() { return $this->content; } /** * @return string */ public function generate() { $output = '@' . $this->name . (! empty($this->content) ? ' ' . $this->content : ''); return $output; } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/LicenseTag.php000066400000000000000000000045661357431215700236360ustar00rootroot00000000000000setUrl($url); } if (! empty($licenseName)) { $this->setLicenseName($licenseName); } } /** * @param ReflectionTagInterface $reflectionTag * @return ReturnTag * @deprecated Deprecated in 2.3. Use TagManager::createTagFromReflection() instead */ public static function fromReflection(ReflectionTagInterface $reflectionTag) { $tagManager = new TagManager(); $tagManager->initializeDefaultTags(); return $tagManager->createTagFromReflection($reflectionTag); } /** * @return string */ public function getName() { return 'license'; } /** * @param string $url * @return LicenseTag */ public function setUrl($url) { $this->url = $url; return $this; } /** * @return string */ public function getUrl() { return $this->url; } /** * @param string $name * @return LicenseTag */ public function setLicenseName($name) { $this->licenseName = $name; return $this; } /** * @return string */ public function getLicenseName() { return $this->licenseName; } /** * @return string */ public function generate() { $output = '@license' . (! empty($this->url) ? ' ' . $this->url : '') . (! empty($this->licenseName) ? ' ' . $this->licenseName : ''); return $output; } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/MethodTag.php000066400000000000000000000042031357431215700234600ustar00rootroot00000000000000setMethodName($methodName); } $this->setIsStatic((bool) $isStatic); parent::__construct($types, $description); } /** * @return string */ public function getName() { return 'method'; } /** * @param bool $isStatic * @return MethodTag */ public function setIsStatic($isStatic) { $this->isStatic = $isStatic; return $this; } /** * @return bool */ public function isStatic() { return $this->isStatic; } /** * @param string $methodName * @return MethodTag */ public function setMethodName($methodName) { $this->methodName = rtrim($methodName, ')('); return $this; } /** * @return string */ public function getMethodName() { return $this->methodName; } /** * @return string */ public function generate() { $output = '@method' . ($this->isStatic ? ' static' : '') . (! empty($this->types) ? ' ' . $this->getTypesAsString() : '') . (! empty($this->methodName) ? ' ' . $this->methodName . '()' : '') . (! empty($this->description) ? ' ' . $this->description : ''); return $output; } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/ParamTag.php000066400000000000000000000060711357431215700233050ustar00rootroot00000000000000setVariableName($variableName); } parent::__construct($types, $description); } /** * @param ReflectionTagInterface $reflectionTag * @return ParamTag * @deprecated Deprecated in 2.3. Use TagManager::createTagFromReflection() instead */ public static function fromReflection(ReflectionTagInterface $reflectionTag) { $tagManager = new TagManager(); $tagManager->initializeDefaultTags(); return $tagManager->createTagFromReflection($reflectionTag); } /** * @return string */ public function getName() { return 'param'; } /** * @param string $variableName * @return ParamTag */ public function setVariableName($variableName) { $this->variableName = ltrim($variableName, '$'); return $this; } /** * @return string */ public function getVariableName() { return $this->variableName; } /** * @param string $datatype * @return ParamTag * @deprecated Deprecated in 2.3. Use setTypes() instead */ public function setDatatype($datatype) { return $this->setTypes($datatype); } /** * @return string * @deprecated Deprecated in 2.3. Use getTypes() or getTypesAsString() instead */ public function getDatatype() { return $this->getTypesAsString(); } /** * @param string $paramName * @return ParamTag * @deprecated Deprecated in 2.3. Use setVariableName() instead */ public function setParamName($paramName) { return $this->setVariableName($paramName); } /** * @return string * @deprecated Deprecated in 2.3. Use getVariableName() instead */ public function getParamName() { return $this->getVariableName(); } /** * @return string */ public function generate() { $output = '@param' . (! empty($this->types) ? ' ' . $this->getTypesAsString() : '') . (! empty($this->variableName) ? ' $' . $this->variableName : '') . (! empty($this->description) ? ' ' . $this->description : ''); return $output; } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/PropertyTag.php000066400000000000000000000032371357431215700240720ustar00rootroot00000000000000setPropertyName($propertyName); } parent::__construct($types, $description); } /** * @return string */ public function getName() { return 'property'; } /** * @param string $propertyName * @return self */ public function setPropertyName($propertyName) { $this->propertyName = ltrim($propertyName, '$'); return $this; } /** * @return string */ public function getPropertyName() { return $this->propertyName; } /** * @return string */ public function generate() { $output = '@property' . (! empty($this->types) ? ' ' . $this->getTypesAsString() : '') . (! empty($this->propertyName) ? ' $' . $this->propertyName : '') . (! empty($this->description) ? ' ' . $this->description : ''); return $output; } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/ReturnTag.php000066400000000000000000000033551357431215700235260ustar00rootroot00000000000000initializeDefaultTags(); return $tagManager->createTagFromReflection($reflectionTag); } /** * @return string */ public function getName() { return 'return'; } /** * @param string $datatype * @return ReturnTag * @deprecated Deprecated in 2.3. Use setTypes() instead */ public function setDatatype($datatype) { return $this->setTypes($datatype); } /** * @return string * @deprecated Deprecated in 2.3. Use getTypes() or getTypesAsString() instead */ public function getDatatype() { return $this->getTypesAsString(); } /** * @return string */ public function generate() { $output = '@return ' . $this->getTypesAsString() . (! empty($this->description) ? ' ' . $this->description : ''); return $output; } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/TagInterface.php000066400000000000000000000007161357431215700241450ustar00rootroot00000000000000types) ? ' ' . $this->getTypesAsString() : '') . (! empty($this->description) ? ' ' . $this->description : ''); return $output; } } php-zend-code-3.4.1/src/Generator/DocBlock/Tag/VarTag.php000066400000000000000000000034571357431215700230020ustar00rootroot00000000000000variableName = ltrim($variableName, '$'); } parent::__construct($types, $description); } /** * {@inheritDoc} */ public function getName() : string { return 'var'; } /** * @internal this code is only public for compatibility with the * @see \Zend\Code\Generator\DocBlock\TagManager, which * uses setters */ public function setVariableName(?string $variableName) : void { if (null !== $variableName) { $this->variableName = ltrim($variableName, '$'); } } public function getVariableName() : ?string { return $this->variableName; } /** * {@inheritDoc} */ public function generate() : string { return '@var' . ((! empty($this->types)) ? ' ' . $this->getTypesAsString() : '') . (null !== $this->variableName ? ' $' . $this->variableName : '') . ((! empty($this->description)) ? ' ' . $this->description : ''); } } php-zend-code-3.4.1/src/Generator/DocBlock/TagManager.php000066400000000000000000000053011357431215700230770ustar00rootroot00000000000000addPrototype(new Tag\ParamTag()); $this->addPrototype(new Tag\ReturnTag()); $this->addPrototype(new Tag\MethodTag()); $this->addPrototype(new Tag\PropertyTag()); $this->addPrototype(new Tag\AuthorTag()); $this->addPrototype(new Tag\LicenseTag()); $this->addPrototype(new Tag\ThrowsTag()); $this->addPrototype(new Tag\VarTag()); $this->setGenericPrototype(new Tag\GenericTag()); } /** * @param ReflectionTagInterface $reflectionTag * @return TagInterface */ public function createTagFromReflection(ReflectionTagInterface $reflectionTag) { $tagName = $reflectionTag->getName(); /* @var TagInterface $newTag */ $newTag = $this->getClonedPrototype($tagName); // transport any properties via accessors and mutators from reflection to codegen object $reflectionClass = new \ReflectionClass($reflectionTag); foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { if (0 === strpos($method->getName(), 'get')) { $propertyName = substr($method->getName(), 3); if (method_exists($newTag, 'set' . $propertyName)) { $newTag->{'set' . $propertyName}($reflectionTag->{'get' . $propertyName}()); } } elseif (0 === strpos($method->getName(), 'is')) { $propertyName = ucfirst($method->getName()); if (method_exists($newTag, 'set' . $propertyName)) { $newTag->{'set' . $propertyName}($reflectionTag->{$method->getName()}()); } } } return $newTag; } } php-zend-code-3.4.1/src/Generator/DocBlockGenerator.php000066400000000000000000000162101357431215700227410ustar00rootroot00000000000000setSourceContent($reflectionDocBlock->getContents()); $docBlock->setSourceDirty(false); $docBlock->setShortDescription($reflectionDocBlock->getShortDescription()); $docBlock->setLongDescription($reflectionDocBlock->getLongDescription()); foreach ($reflectionDocBlock->getTags() as $tag) { $docBlock->setTag(self::getTagManager()->createTagFromReflection($tag)); } return $docBlock; } /** * Generate from array * * @configkey shortdescription string The short description for this doc block * @configkey longdescription string The long description for this doc block * @configkey tags array * * @throws Exception\InvalidArgumentException * @param array $array * @return DocBlockGenerator */ public static function fromArray(array $array) { $docBlock = new static(); foreach ($array as $name => $value) { // normalize key switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { case 'shortdescription': $docBlock->setShortDescription($value); break; case 'longdescription': $docBlock->setLongDescription($value); break; case 'tags': $docBlock->setTags($value); break; } } return $docBlock; } /** * @return TagManager */ protected static function getTagManager() { if (! isset(static::$tagManager)) { static::$tagManager = new TagManager(); static::$tagManager->initializeDefaultTags(); } return static::$tagManager; } /** * @param string $shortDescription * @param string $longDescription * @param array $tags */ public function __construct($shortDescription = null, $longDescription = null, array $tags = []) { if ($shortDescription) { $this->setShortDescription($shortDescription); } if ($longDescription) { $this->setLongDescription($longDescription); } if (is_array($tags) && $tags) { $this->setTags($tags); } } /** * @param string $shortDescription * @return DocBlockGenerator */ public function setShortDescription($shortDescription) { $this->shortDescription = $shortDescription; return $this; } /** * @return string */ public function getShortDescription() { return $this->shortDescription; } /** * @param string $longDescription * @return DocBlockGenerator */ public function setLongDescription($longDescription) { $this->longDescription = $longDescription; return $this; } /** * @return string */ public function getLongDescription() { return $this->longDescription; } /** * @param array $tags * @return DocBlockGenerator */ public function setTags(array $tags) { foreach ($tags as $tag) { $this->setTag($tag); } return $this; } /** * @param array|TagInterface $tag * @throws Exception\InvalidArgumentException * @return DocBlockGenerator */ public function setTag($tag) { if (is_array($tag)) { // use deprecated Tag class for backward compatibility to old array-keys $genericTag = new Tag(); $genericTag->setOptions($tag); $tag = $genericTag; } elseif (! $tag instanceof TagInterface) { throw new Exception\InvalidArgumentException(sprintf( '%s expects either an array of method options or an instance of %s\DocBlock\Tag\TagInterface', __METHOD__, __NAMESPACE__ )); } $this->tags[] = $tag; return $this; } /** * @return TagInterface[] */ public function getTags() { return $this->tags; } /** * @param bool $value * @return DocBlockGenerator */ public function setWordWrap($value) { $this->wordwrap = (bool) $value; return $this; } /** * @return bool */ public function getWordWrap() { return $this->wordwrap; } /** * @return string */ public function generate() { if (! $this->isSourceDirty()) { return $this->docCommentize(trim($this->getSourceContent())); } $output = ''; if (null !== ($sd = $this->getShortDescription())) { $output .= $sd . self::LINE_FEED . self::LINE_FEED; } if (null !== ($ld = $this->getLongDescription())) { $output .= $ld . self::LINE_FEED . self::LINE_FEED; } /* @var $tag GeneratorInterface */ foreach ($this->getTags() as $tag) { $output .= $tag->generate() . self::LINE_FEED; } return $this->docCommentize(trim($output)); } /** * @param string $content * @return string */ protected function docCommentize($content) { $indent = $this->getIndentation(); $output = $indent . '/**' . self::LINE_FEED; $content = $this->getWordWrap() == true ? wordwrap($content, 80, self::LINE_FEED) : $content; $lines = explode(self::LINE_FEED, $content); foreach ($lines as $line) { $output .= $indent . ' *'; if ($line) { $output .= ' ' . $line; } $output .= self::LINE_FEED; } $output .= $indent . ' */' . self::LINE_FEED; return $output; } } php-zend-code-3.4.1/src/Generator/Exception/000077500000000000000000000000001357431215700206375ustar00rootroot00000000000000php-zend-code-3.4.1/src/Generator/Exception/ExceptionInterface.php000066400000000000000000000007151357431215700251320ustar00rootroot00000000000000setOptions($options); } } /** * Use this if you intend on generating code generation objects based on the same file. * This will keep previous changes to the file in tact during the same PHP process * * @param string $filePath * @param bool $includeIfNotAlreadyIncluded * @throws ReflectionException\InvalidArgumentException If file does not exists * @throws ReflectionException\RuntimeException If file exists but is not included or required * @return FileGenerator */ public static function fromReflectedFileName($filePath, $includeIfNotAlreadyIncluded = true) { $fileReflector = new FileReflection($filePath, $includeIfNotAlreadyIncluded); $codeGenerator = static::fromReflection($fileReflector); return $codeGenerator; } /** * @param FileReflection $fileReflection * @return FileGenerator */ public static function fromReflection(FileReflection $fileReflection) { $file = new static(); $file->setSourceContent($fileReflection->getContents()); $file->setSourceDirty(false); $uses = $fileReflection->getUses(); foreach ($fileReflection->getClasses() as $class) { $phpClass = ClassGenerator::fromReflection($class); $phpClass->setContainingFileGenerator($file); foreach ($uses as $fileUse) { $phpClass->addUse($fileUse['use'], $fileUse['as']); } $file->setClass($phpClass); } $namespace = $fileReflection->getNamespace(); if ($namespace != '') { $file->setNamespace($namespace); } if ($uses) { $file->setUses($uses); } if ($fileReflection->getDocComment() != '') { $docBlock = $fileReflection->getDocBlock(); $file->setDocBlock(DocBlockGenerator::fromReflection($docBlock)); } return $file; } /** * @param array $values * @return FileGenerator */ public static function fromArray(array $values) { $fileGenerator = new static(); foreach ($values as $name => $value) { switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { case 'filename': $fileGenerator->setFilename($value); break; case 'class': $fileGenerator->setClass( $value instanceof ClassGenerator ? $value : ClassGenerator::fromArray($value) ); break; case 'requiredfiles': $fileGenerator->setRequiredFiles($value); break; case 'declares': $fileGenerator->setDeclares(array_map(static function ($directive, $value) { return DeclareStatement::fromArray([$directive => $value]); }, array_keys($value), $value)); break; default: if (property_exists($fileGenerator, $name)) { $fileGenerator->{$name} = $value; } elseif (method_exists($fileGenerator, 'set' . $name)) { $fileGenerator->{'set' . $name}($value); } } } return $fileGenerator; } /** * @param DocBlockGenerator|array|string $docBlock * @throws Exception\InvalidArgumentException * @return FileGenerator */ public function setDocBlock($docBlock) { if (is_string($docBlock)) { $docBlock = ['shortDescription' => $docBlock]; } if (is_array($docBlock)) { $docBlock = new DocBlockGenerator($docBlock); } elseif (! $docBlock instanceof DocBlockGenerator) { throw new Exception\InvalidArgumentException(sprintf( '%s is expecting either a string, array or an instance of %s\DocBlockGenerator', __METHOD__, __NAMESPACE__ )); } $this->docBlock = $docBlock; return $this; } /** * @return DocBlockGenerator */ public function getDocBlock() { return $this->docBlock; } /** * @param array $requiredFiles * @return FileGenerator */ public function setRequiredFiles(array $requiredFiles) { $this->requiredFiles = $requiredFiles; return $this; } /** * @return array */ public function getRequiredFiles() { return $this->requiredFiles; } /** * @return string */ public function getNamespace() { return $this->namespace; } /** * @param string $namespace * @return FileGenerator */ public function setNamespace($namespace) { $this->namespace = (string) $namespace; return $this; } /** * Returns an array with the first element the use statement, second is the as part. * If $withResolvedAs is set to true, there will be a third element that is the * "resolved" as statement, as the second part is not required in use statements * * @param bool $withResolvedAs * @return array */ public function getUses($withResolvedAs = false) { $uses = $this->uses; if ($withResolvedAs) { for ($useIndex = 0, $count = count($uses); $useIndex < $count; $useIndex++) { if ($uses[$useIndex][1] == '') { if (($lastSeparator = strrpos($uses[$useIndex][0], '\\')) !== false) { $uses[$useIndex][2] = substr($uses[$useIndex][0], $lastSeparator + 1); } else { $uses[$useIndex][2] = $uses[$useIndex][0]; } } else { $uses[$useIndex][2] = $uses[$useIndex][1]; } } } return $uses; } /** * @param array $uses * @return FileGenerator */ public function setUses(array $uses) { foreach ($uses as $use) { $use = (array) $use; if (array_key_exists('use', $use) && array_key_exists('as', $use)) { $import = $use['use']; $alias = $use['as']; } elseif (count($use) == 2) { list($import, $alias) = $use; } else { $import = current($use); $alias = null; } $this->setUse($import, $alias); } return $this; } /** * @param string $use * @param null|string $as * @return FileGenerator */ public function setUse($use, $as = null) { if (! in_array([$use, $as], $this->uses)) { $this->uses[] = [$use, $as]; } return $this; } /** * @param array $classes * @return FileGenerator */ public function setClasses(array $classes) { foreach ($classes as $class) { $this->setClass($class); } return $this; } /** * @param string $name * @return ClassGenerator */ public function getClass($name = null) { if ($name === null) { reset($this->classes); return current($this->classes); } return $this->classes[(string) $name]; } /** * @param array|string|ClassGenerator $class * @throws Exception\InvalidArgumentException * @return FileGenerator */ public function setClass($class) { if (is_array($class)) { $class = ClassGenerator::fromArray($class); } elseif (is_string($class)) { $class = new ClassGenerator($class); } elseif (! $class instanceof ClassGenerator) { throw new Exception\InvalidArgumentException(sprintf( '%s is expecting either a string, array or an instance of %s\ClassGenerator', __METHOD__, __NAMESPACE__ )); } // @todo check for dup here $className = $class->getName(); $this->classes[$className] = $class; return $this; } /** * @param string $filename * @return FileGenerator */ public function setFilename($filename) { $this->filename = (string) $filename; return $this; } /** * @return string */ public function getFilename() { return $this->filename; } /** * @return ClassGenerator[] */ public function getClasses() { return $this->classes; } /** * @param string $body * @return FileGenerator */ public function setBody($body) { $this->body = (string) $body; return $this; } /** * @return string */ public function getBody() { return $this->body; } public function setDeclares(array $declares) { foreach ($declares as $declare) { if (! $declare instanceof DeclareStatement) { throw new InvalidArgumentException(sprintf( '%s is expecting an array of %s objects', __METHOD__, DeclareStatement::class )); } if (! array_key_exists($declare->getDirective(), $this->declares)) { $this->declares[$declare->getDirective()] = $declare; } } return $this; } /** * @return bool */ public function isSourceDirty() { $docBlock = $this->getDocBlock(); if ($docBlock && $docBlock->isSourceDirty()) { return true; } foreach ($this->classes as $class) { if ($class->isSourceDirty()) { return true; } } return parent::isSourceDirty(); } /** * @return string */ public function generate() { if ($this->isSourceDirty() === false) { return $this->sourceContent; } $output = ''; // @note body gets populated when FileGenerator created // from a file. @see fromReflection and may also be set // via FileGenerator::setBody $body = $this->getBody(); // start with the body (if there), or open tag if (preg_match('#(?:\s*)<\?php#', $body) == false) { $output = 'getDocBlock())) { $docBlock->setIndentation(''); if (preg_match('#/\* Zend_Code_Generator_FileGenerator-DocBlockMarker \*/#m', $output)) { // @codingStandardsIgnoreStart $output = preg_replace('#/\* Zend_Code_Generator_FileGenerator-DocBlockMarker \*/#m', $docBlock->generate(), $output, 1); // @codingStandardsIgnoreEnd } else { $output .= $docBlock->generate() . self::LINE_FEED; } } // newline $output .= self::LINE_FEED; // namespace, if any $namespace = $this->getNamespace(); if ($namespace) { $namespace = sprintf('namespace %s;%s', $namespace, str_repeat(self::LINE_FEED, 2)); if (preg_match('#/\* Zend_Code_Generator_FileGenerator-NamespaceMarker \*/#m', $output)) { $output = preg_replace( '#/\* Zend_Code_Generator_FileGenerator-NamespaceMarker \*/#m', $namespace, $output, 1 ); } else { $output .= $namespace; } } // declares, if any if ($this->declares) { $declareStatements = ''; foreach ($this->declares as $declare) { $declareStatements .= $declare->getStatement() . self::LINE_FEED; } if (preg_match('#/\* Zend_Code_Generator_FileGenerator-DeclaresMarker \*/#m', $output)) { $output = preg_replace( '#/\* Zend_Code_Generator_FileGenerator-DeclaresMarker \*/#m', $declareStatements, $output, 1 ); } else { $output .= $declareStatements; } $output .= self::LINE_FEED; } // process required files // @todo marker replacement for required files $requiredFiles = $this->getRequiredFiles(); if (! empty($requiredFiles)) { foreach ($requiredFiles as $requiredFile) { $output .= 'require_once \'' . $requiredFile . '\';' . self::LINE_FEED; } $output .= self::LINE_FEED; } $classes = $this->getClasses(); $classUses = []; //build uses array foreach ($classes as $class) { //check for duplicate use statements $uses = $class->getUses(); if (! empty($uses) && is_array($uses)) { $classUses = array_merge($classUses, $uses); } } // process import statements $uses = $this->getUses(); if (! empty($uses)) { $useOutput = ''; foreach ($uses as $use) { list($import, $alias) = $use; if (null === $alias) { $tempOutput = sprintf('%s', $import); } else { $tempOutput = sprintf('%s as %s', $import, $alias); } //don't duplicate use statements if (! in_array($tempOutput, $classUses)) { $useOutput .= 'use ' . $tempOutput . ';'; $useOutput .= self::LINE_FEED; } } $useOutput .= self::LINE_FEED; if (preg_match('#/\* Zend_Code_Generator_FileGenerator-UseMarker \*/#m', $output)) { $output = preg_replace( '#/\* Zend_Code_Generator_FileGenerator-UseMarker \*/#m', $useOutput, $output, 1 ); } else { $output .= $useOutput; } } // process classes if (! empty($classes)) { foreach ($classes as $class) { // @codingStandardsIgnoreStart $regex = str_replace('&', $class->getName(), '/\* Zend_Code_Generator_Php_File-ClassMarker: \{[A-Za-z0-9\\\]+?&\} \*/'); // @codingStandardsIgnoreEnd if (preg_match('#' . $regex . '#m', $output)) { $output = preg_replace('#' . $regex . '#', $class->generate(), $output, 1); } else { if ($namespace) { $class->setNamespaceName(null); } $output .= $class->generate() . self::LINE_FEED; } } } if (! empty($body)) { // add an extra space between classes and if (! empty($classes)) { $output .= self::LINE_FEED; } $output .= $body; } return $output; } /** * @return FileGenerator * @throws Exception\RuntimeException */ public function write() { if ($this->filename == '' || ! is_writable(dirname($this->filename))) { throw new Exception\RuntimeException('This code generator object is not writable.'); } file_put_contents($this->filename, $this->generate()); return $this; } } php-zend-code-3.4.1/src/Generator/FileGeneratorRegistry.php000066400000000000000000000025371357431215700237000ustar00rootroot00000000000000getFilename(); } if ($fileName == '') { throw new RuntimeException('FileName does not exist.'); } // cannot use realpath since the file might not exist, but we do need to have the index // in the same DIRECTORY_SEPARATOR that realpath would use: $fileName = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $fileName); static::$fileCodeGenerators[$fileName] = $fileCodeGenerator; } } php-zend-code-3.4.1/src/Generator/GeneratorInterface.php000066400000000000000000000006271357431215700231660ustar00rootroot00000000000000isInterface()) { throw new Exception\InvalidArgumentException(sprintf( 'Class %s is not a interface', $classReflection->getName() )); } // class generator $cg = new static($classReflection->getName()); $methods = []; $cg->setSourceContent($cg->getSourceContent()); $cg->setSourceDirty(false); if ($classReflection->getDocComment() != '') { $cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock())); } // set the namespace if ($classReflection->inNamespace()) { $cg->setNamespaceName($classReflection->getNamespaceName()); } foreach ($classReflection->getMethods() as $reflectionMethod) { $className = $cg->getNamespaceName() ? $cg->getNamespaceName() . '\\' . $cg->getName() : $cg->getName(); if ($reflectionMethod->getDeclaringClass()->getName() == $className) { $methods[] = MethodGenerator::fromReflection($reflectionMethod); } } foreach ($classReflection->getConstants() as $name => $value) { $cg->addConstant($name, $value); } $cg->addMethods($methods); return $cg; } /** * Generate from array * * @configkey name string [required] Class Name * @configkey filegenerator FileGenerator File generator that holds this class * @configkey namespacename string The namespace for this class * @configkey docblock string The docblock information * @configkey constants * @configkey methods * * @throws Exception\InvalidArgumentException * @param array $array * @return InterfaceGenerator */ public static function fromArray(array $array) { if (! isset($array['name'])) { throw new Exception\InvalidArgumentException( 'Class generator requires that a name is provided for this object' ); } $cg = new static($array['name']); foreach ($array as $name => $value) { // normalize key switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { case 'containingfile': $cg->setContainingFileGenerator($value); break; case 'namespacename': $cg->setNamespaceName($value); break; case 'docblock': $docBlock = $value instanceof DocBlockGenerator ? $value : DocBlockGenerator::fromArray($value); $cg->setDocBlock($docBlock); break; case 'methods': $cg->addMethods($value); break; case 'constants': $cg->addConstants($value); break; } } return $cg; } /** * {@inheritDoc} */ public function addPropertyFromGenerator(PropertyGenerator $property) { return $this; } /** * {@inheritDoc} */ public function addMethodFromGenerator(MethodGenerator $method) { $method->setInterface(true); return parent::addMethodFromGenerator($method); } /** * {@inheritDoc} */ public function setExtendedClass($extendedClass) { return $this; } /** * {@inheritDoc} */ public function setAbstract($isAbstract) { return $this; } } php-zend-code-3.4.1/src/Generator/MethodGenerator.php000066400000000000000000000300171357431215700225020ustar00rootroot00000000000000setSourceContent($reflectionMethod->getContents(false)); $method->setSourceDirty(false); if ($reflectionMethod->getDocComment() != '') { $method->setDocBlock(DocBlockGenerator::fromReflection($reflectionMethod->getDocBlock())); } $method->setBody(static::clearBodyIndention($reflectionMethod->getBody())); return $method; } /** * Returns a MethodGenerator based on a MethodReflection with only the signature copied. * * This is similar to fromReflection() but without the method body and phpdoc as this is quite heavy to copy. * It's for example useful when creating proxies where you normally change the method body anyway. */ public static function copyMethodSignature(MethodReflection $reflectionMethod): MethodGenerator { $method = new static(); $declaringClass = $reflectionMethod->getDeclaringClass(); $method->setReturnType(self::extractReturnTypeFromMethodReflection($reflectionMethod)); $method->setFinal($reflectionMethod->isFinal()); if ($reflectionMethod->isPrivate()) { $method->setVisibility(self::VISIBILITY_PRIVATE); } elseif ($reflectionMethod->isProtected()) { $method->setVisibility(self::VISIBILITY_PROTECTED); } else { $method->setVisibility(self::VISIBILITY_PUBLIC); } $method->setInterface($declaringClass->isInterface()); $method->setStatic($reflectionMethod->isStatic()); $method->setReturnsReference($reflectionMethod->returnsReference()); $method->setName($reflectionMethod->getName()); foreach ($reflectionMethod->getParameters() as $reflectionParameter) { $method->setParameter(ParameterGenerator::fromReflection($reflectionParameter)); } return $method; } /** * Identify the space indention from the first line and remove this indention * from all lines * * @param string $body * * @return string */ protected static function clearBodyIndention($body) { if (empty($body)) { return $body; } $lines = explode("\n", $body); $indention = str_replace(trim($lines[1]), '', $lines[1]); foreach ($lines as $key => $line) { if (substr($line, 0, strlen($indention)) == $indention) { $lines[$key] = substr($line, strlen($indention)); } } $body = implode("\n", $lines); return $body; } /** * Generate from array * * @configkey name string [required] Class Name * @configkey docblock string The docblock information * @configkey flags int Flags, one of MethodGenerator::FLAG_ABSTRACT MethodGenerator::FLAG_FINAL * @configkey parameters string Class which this class is extending * @configkey body string * @configkey abstract bool * @configkey final bool * @configkey static bool * @configkey visibility string * * @throws Exception\InvalidArgumentException * @param array $array * @return MethodGenerator */ public static function fromArray(array $array) { if (! isset($array['name'])) { throw new Exception\InvalidArgumentException( 'Method generator requires that a name is provided for this object' ); } $method = new static($array['name']); foreach ($array as $name => $value) { // normalize key switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { case 'docblock': $docBlock = $value instanceof DocBlockGenerator ? $value : DocBlockGenerator::fromArray($value); $method->setDocBlock($docBlock); break; case 'flags': $method->setFlags($value); break; case 'parameters': $method->setParameters($value); break; case 'body': $method->setBody($value); break; case 'abstract': $method->setAbstract($value); break; case 'final': $method->setFinal($value); break; case 'interface': $method->setInterface($value); break; case 'static': $method->setStatic($value); break; case 'visibility': $method->setVisibility($value); break; case 'returntype': $method->setReturnType($value); break; } } return $method; } /** * @param string $name * @param array $parameters * @param int $flags * @param string $body * @param DocBlockGenerator|string $docBlock */ public function __construct( $name = null, array $parameters = [], $flags = self::FLAG_PUBLIC, $body = null, $docBlock = null ) { if ($name) { $this->setName($name); } if ($parameters) { $this->setParameters($parameters); } if ($flags !== self::FLAG_PUBLIC) { $this->setFlags($flags); } if ($body) { $this->setBody($body); } if ($docBlock) { $this->setDocBlock($docBlock); } } /** * @param array $parameters * @return MethodGenerator */ public function setParameters(array $parameters) { foreach ($parameters as $parameter) { $this->setParameter($parameter); } return $this; } /** * @param ParameterGenerator|array|string $parameter * @throws Exception\InvalidArgumentException * @return MethodGenerator */ public function setParameter($parameter) { if (is_string($parameter)) { $parameter = new ParameterGenerator($parameter); } if (is_array($parameter)) { $parameter = ParameterGenerator::fromArray($parameter); } if (! $parameter instanceof ParameterGenerator) { throw new Exception\InvalidArgumentException(sprintf( '%s is expecting either a string, array or an instance of %s\ParameterGenerator', __METHOD__, __NAMESPACE__ )); } $this->parameters[$parameter->getName()] = $parameter; return $this; } /** * @return ParameterGenerator[] */ public function getParameters() { return $this->parameters; } /** * @param string $body * @return MethodGenerator */ public function setBody($body) { $this->body = $body; return $this; } /** * @return string */ public function getBody() { return $this->body; } /** * @param string|null $returnType * * @return MethodGenerator */ public function setReturnType($returnType = null) { $this->returnType = null === $returnType ? null : TypeGenerator::fromTypeString($returnType); return $this; } /** * @return TypeGenerator|null */ public function getReturnType() { return $this->returnType; } /** * @param bool $returnsReference * * @return MethodGenerator */ public function setReturnsReference($returnsReference) { $this->returnsReference = (bool) $returnsReference; return $this; } /** * @return string */ public function generate() { $output = ''; $indent = $this->getIndentation(); if (($docBlock = $this->getDocBlock()) !== null) { $docBlock->setIndentation($indent); $output .= $docBlock->generate(); } $output .= $indent; if ($this->isAbstract()) { $output .= 'abstract '; } else { $output .= $this->isFinal() ? 'final ' : ''; } $output .= $this->getVisibility() . ($this->isStatic() ? ' static' : '') . ' function ' . ($this->returnsReference ? '& ' : '') . $this->getName() . '('; $parameters = $this->getParameters(); if (! empty($parameters)) { foreach ($parameters as $parameter) { $parameterOutput[] = $parameter->generate(); } $output .= implode(', ', $parameterOutput); } $output .= ')'; if ($this->returnType) { $output .= ' : ' . $this->returnType->generate(); } if ($this->isAbstract()) { return $output . ';'; } if ($this->isInterface()) { return $output . ';'; } $output .= self::LINE_FEED . $indent . '{' . self::LINE_FEED; if ($this->body) { $output .= preg_replace('#^((?![a-zA-Z0-9_-]+;).+?)$#m', $indent . $indent . '$1', trim($this->body)) . self::LINE_FEED; } $output .= $indent . '}' . self::LINE_FEED; return $output; } public function __toString() { return $this->generate(); } /** * @param MethodReflection $methodReflection * * @return null|string */ private static function extractReturnTypeFromMethodReflection(MethodReflection $methodReflection) { $returnType = method_exists($methodReflection, 'getReturnType') ? $methodReflection->getReturnType() : null; if (! $returnType) { return null; } if (! method_exists($returnType, 'getName')) { return self::expandLiteralType((string) $returnType, $methodReflection); } return ($returnType->allowsNull() ? '?' : '') . self::expandLiteralType($returnType->getName(), $methodReflection); } /** * @param string $literalReturnType * @param ReflectionMethod $methodReflection * * @return string */ private static function expandLiteralType($literalReturnType, ReflectionMethod $methodReflection) { if ('self' === strtolower($literalReturnType)) { return $methodReflection->getDeclaringClass()->getName(); } if ('parent' === strtolower($literalReturnType)) { return $methodReflection->getDeclaringClass()->getParentClass()->getName(); } return $literalReturnType; } } php-zend-code-3.4.1/src/Generator/ParameterGenerator.php000066400000000000000000000244771357431215700232170ustar00rootroot00000000000000setName($reflectionParameter->getName()); if ($type = self::extractFQCNTypeFromReflectionType($reflectionParameter)) { $param->setType($type); } $param->setPosition($reflectionParameter->getPosition()); $variadic = method_exists($reflectionParameter, 'isVariadic') && $reflectionParameter->isVariadic(); $param->setVariadic($variadic); if (! $variadic && ($reflectionParameter->isOptional() || $reflectionParameter->isDefaultValueAvailable())) { try { $param->setDefaultValue($reflectionParameter->getDefaultValue()); } catch (\ReflectionException $e) { $param->setDefaultValue(null); } } $param->setPassedByReference($reflectionParameter->isPassedByReference()); return $param; } /** * Generate from array * * @configkey name string [required] Class Name * @configkey type string * @configkey defaultvalue null|bool|string|int|float|array|ValueGenerator * @configkey passedbyreference bool * @configkey position int * @configkey sourcedirty bool * @configkey indentation string * @configkey sourcecontent string * @configkey omitdefaultvalue bool * * @throws Exception\InvalidArgumentException * @param array $array * @return ParameterGenerator */ public static function fromArray(array $array) { if (! isset($array['name'])) { throw new Exception\InvalidArgumentException( 'Parameter generator requires that a name is provided for this object' ); } $param = new static($array['name']); foreach ($array as $name => $value) { // normalize key switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { case 'type': $param->setType($value); break; case 'defaultvalue': $param->setDefaultValue($value); break; case 'passedbyreference': $param->setPassedByReference($value); break; case 'position': $param->setPosition($value); break; case 'sourcedirty': $param->setSourceDirty($value); break; case 'indentation': $param->setIndentation($value); break; case 'sourcecontent': $param->setSourceContent($value); break; case 'omitdefaultvalue': $param->omitDefaultValue($value); break; } } return $param; } /** * @param string $name * @param string $type * @param mixed $defaultValue * @param int $position * @param bool $passByReference */ public function __construct( $name = null, $type = null, $defaultValue = null, $position = null, $passByReference = false ) { if (null !== $name) { $this->setName($name); } if (null !== $type) { $this->setType($type); } if (null !== $defaultValue) { $this->setDefaultValue($defaultValue); } if (null !== $position) { $this->setPosition($position); } if (false !== $passByReference) { $this->setPassedByReference(true); } } /** * @param string $type * @return ParameterGenerator */ public function setType($type) { $this->type = TypeGenerator::fromTypeString($type); return $this; } /** * @return string */ public function getType() { return $this->type ? (string) $this->type : null; } /** * @param string $name * @return ParameterGenerator */ public function setName($name) { $this->name = (string) $name; return $this; } /** * @return string */ public function getName() { return $this->name; } /** * Set the default value of the parameter. * * Certain variables are difficult to express * * @param null|bool|string|int|float|array|ValueGenerator $defaultValue * @return ParameterGenerator */ public function setDefaultValue($defaultValue) { if (! $defaultValue instanceof ValueGenerator) { $defaultValue = new ValueGenerator($defaultValue); } $this->defaultValue = $defaultValue; return $this; } /** * @return ValueGenerator */ public function getDefaultValue() { return $this->defaultValue; } /** * @param int $position * @return ParameterGenerator */ public function setPosition($position) { $this->position = (int) $position; return $this; } /** * @return int */ public function getPosition() { return $this->position; } /** * @return bool */ public function getPassedByReference() { return $this->passedByReference; } /** * @param bool $passedByReference * @return ParameterGenerator */ public function setPassedByReference($passedByReference) { $this->passedByReference = (bool) $passedByReference; return $this; } /** * @param bool $variadic * * @return ParameterGenerator */ public function setVariadic($variadic) { $this->variadic = (bool) $variadic; return $this; } /** * @return bool */ public function getVariadic() { return $this->variadic; } /** * @return string */ public function generate() { $output = $this->generateTypeHint(); if (true === $this->passedByReference) { $output .= '&'; } if ($this->variadic) { $output .= '... '; } $output .= '$' . $this->name; if ($this->omitDefaultValue) { return $output; } if ($this->defaultValue instanceof ValueGenerator) { $output .= ' = '; $this->defaultValue->setOutputMode(ValueGenerator::OUTPUT_SINGLE_LINE); $output .= $this->defaultValue; } return $output; } /** * @param ParameterReflection $reflectionParameter * * @return null|string */ private static function extractFQCNTypeFromReflectionType(ParameterReflection $reflectionParameter) { if (! method_exists($reflectionParameter, 'getType')) { return self::prePhp7ExtractFQCNTypeFromReflectionType($reflectionParameter); } $type = method_exists($reflectionParameter, 'getType') ? $reflectionParameter->getType() : null; if (! $type) { return null; } if (! method_exists($type, 'getName')) { return self::expandLiteralParameterType((string) $type, $reflectionParameter); } return ($type->allowsNull() ? '?' : '') . self::expandLiteralParameterType($type->getName(), $reflectionParameter); } /** * For ancient PHP versions (yes, you should upgrade to 7.0): * * @param ParameterReflection $reflectionParameter * * @return string|null */ private static function prePhp7ExtractFQCNTypeFromReflectionType(ParameterReflection $reflectionParameter) { if ($reflectionParameter->isCallable()) { return 'callable'; } if ($reflectionParameter->isArray()) { return 'array'; } if ($class = $reflectionParameter->getClass()) { return $class->getName(); } return null; } /** * @param string $literalParameterType * @param ReflectionParameter $reflectionParameter * * @return string */ private static function expandLiteralParameterType($literalParameterType, ReflectionParameter $reflectionParameter) { if ('self' === strtolower($literalParameterType)) { return $reflectionParameter->getDeclaringClass()->getName(); } if ('parent' === strtolower($literalParameterType)) { return $reflectionParameter->getDeclaringClass()->getParentClass()->getName(); } return $literalParameterType; } /** * @return string */ private function generateTypeHint() { if (null === $this->type) { return ''; } return $this->type->generate() . ' '; } /** * @param bool $omit * @return ParameterGenerator */ public function omitDefaultValue(bool $omit = true) { $this->omitDefaultValue = $omit; return $this; } } php-zend-code-3.4.1/src/Generator/PropertyGenerator.php000066400000000000000000000167611357431215700231200ustar00rootroot00000000000000setName($reflectionProperty->getName()); $allDefaultProperties = $reflectionProperty->getDeclaringClass()->getDefaultProperties(); $defaultValue = $allDefaultProperties[$reflectionProperty->getName()]; $property->setDefaultValue($defaultValue); if ($defaultValue === null) { $property->omitDefaultValue = true; } if ($reflectionProperty->getDocComment() != '') { $property->setDocBlock(DocBlockGenerator::fromReflection($reflectionProperty->getDocBlock())); } if ($reflectionProperty->isStatic()) { $property->setStatic(true); } if ($reflectionProperty->isPrivate()) { $property->setVisibility(self::VISIBILITY_PRIVATE); } elseif ($reflectionProperty->isProtected()) { $property->setVisibility(self::VISIBILITY_PROTECTED); } else { $property->setVisibility(self::VISIBILITY_PUBLIC); } $property->setSourceDirty(false); return $property; } /** * Generate from array * * @configkey name string [required] Class Name * @configkey const bool * @configkey defaultvalue null|bool|string|int|float|array|ValueGenerator * @configkey flags int * @configkey abstract bool * @configkey final bool * @configkey static bool * @configkey visibility string * @configkey omitdefaultvalue bool * * @throws Exception\InvalidArgumentException * @param array $array * @return PropertyGenerator */ public static function fromArray(array $array) { if (! isset($array['name'])) { throw new Exception\InvalidArgumentException( 'Property generator requires that a name is provided for this object' ); } $property = new static($array['name']); foreach ($array as $name => $value) { // normalize key switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { case 'const': $property->setConst($value); break; case 'defaultvalue': $property->setDefaultValue($value); break; case 'docblock': $docBlock = $value instanceof DocBlockGenerator ? $value : DocBlockGenerator::fromArray($value); $property->setDocBlock($docBlock); break; case 'flags': $property->setFlags($value); break; case 'abstract': $property->setAbstract($value); break; case 'final': $property->setFinal($value); break; case 'static': $property->setStatic($value); break; case 'visibility': $property->setVisibility($value); break; case 'omitdefaultvalue': $property->omitDefaultValue($value); break; } } return $property; } /** * @param string $name * @param PropertyValueGenerator|string|array $defaultValue * @param int $flags */ public function __construct($name = null, $defaultValue = null, $flags = self::FLAG_PUBLIC) { if (null !== $name) { $this->setName($name); } if (null !== $defaultValue) { $this->setDefaultValue($defaultValue); } if ($flags !== self::FLAG_PUBLIC) { $this->setFlags($flags); } } /** * @param bool $const * @return PropertyGenerator */ public function setConst($const) { if ($const) { $this->setFlags(self::FLAG_CONSTANT); } else { $this->removeFlag(self::FLAG_CONSTANT); } return $this; } /** * @return bool */ public function isConst() { return (bool) ($this->flags & self::FLAG_CONSTANT); } /** * @param PropertyValueGenerator|mixed $defaultValue * @param string $defaultValueType * @param string $defaultValueOutputMode * * @return PropertyGenerator */ public function setDefaultValue( $defaultValue, $defaultValueType = PropertyValueGenerator::TYPE_AUTO, $defaultValueOutputMode = PropertyValueGenerator::OUTPUT_MULTIPLE_LINE ) { if (! $defaultValue instanceof PropertyValueGenerator) { $defaultValue = new PropertyValueGenerator($defaultValue, $defaultValueType, $defaultValueOutputMode); } $this->defaultValue = $defaultValue; return $this; } /** * @return PropertyValueGenerator */ public function getDefaultValue() { return $this->defaultValue; } /** * @throws Exception\RuntimeException * @return string */ public function generate() { $name = $this->getName(); $defaultValue = $this->getDefaultValue(); $output = ''; if (($docBlock = $this->getDocBlock()) !== null) { $docBlock->setIndentation(' '); $output .= $docBlock->generate(); } if ($this->isConst()) { if ($defaultValue !== null && ! $defaultValue->isValidConstantType()) { throw new Exception\RuntimeException(sprintf( 'The property %s is said to be ' . 'constant but does not have a valid constant value.', $this->name )); } $output .= $this->indentation . $this->getVisibility() . ' const ' . $name . ' = ' . ($defaultValue !== null ? $defaultValue->generate() : 'null;'); return $output; } $output .= $this->indentation . $this->getVisibility() . ($this->isStatic() ? ' static' : '') . ' $' . $name; if ($this->omitDefaultValue) { return $output . ';'; } return $output . ' = ' . ($defaultValue !== null ? $defaultValue->generate() : 'null;'); } /** * @param bool $omit * @return PropertyGenerator */ public function omitDefaultValue(bool $omit = true) { $this->omitDefaultValue = $omit; return $this; } } php-zend-code-3.4.1/src/Generator/PropertyValueGenerator.php000066400000000000000000000010501357431215700240760ustar00rootroot00000000000000getName()); $cg->setSourceContent($cg->getSourceContent()); $cg->setSourceDirty(false); if ($classReflection->getDocComment() != '') { $cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock())); } // set the namespace if ($classReflection->inNamespace()) { $cg->setNamespaceName($classReflection->getNamespaceName()); } $properties = []; foreach ($classReflection->getProperties() as $reflectionProperty) { if ($reflectionProperty->getDeclaringClass()->getName() == $classReflection->getName()) { $properties[] = PropertyGenerator::fromReflection($reflectionProperty); } } $cg->addProperties($properties); $methods = []; foreach ($classReflection->getMethods() as $reflectionMethod) { $className = $cg->getNamespaceName() ? $cg->getNamespaceName() . '\\' . $cg->getName() : $cg->getName(); if ($reflectionMethod->getDeclaringClass()->getName() == $className) { $methods[] = MethodGenerator::fromReflection($reflectionMethod); } } $cg->addMethods($methods); return $cg; } /** * Generate from array * * @configkey name string [required] Class Name * @configkey filegenerator FileGenerator File generator that holds this class * @configkey namespacename string The namespace for this class * @configkey docblock string The docblock information * @configkey properties * @configkey methods * * @throws Exception\InvalidArgumentException * @param array $array * @return TraitGenerator */ public static function fromArray(array $array) { if (! isset($array['name'])) { throw new Exception\InvalidArgumentException( 'Class generator requires that a name is provided for this object' ); } $cg = new static($array['name']); foreach ($array as $name => $value) { // normalize key switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { case 'containingfile': $cg->setContainingFileGenerator($value); break; case 'namespacename': $cg->setNamespaceName($value); break; case 'docblock': $docBlock = $value instanceof DocBlockGenerator ? $value : DocBlockGenerator::fromArray($value); $cg->setDocBlock($docBlock); break; case 'properties': $cg->addProperties($value); break; case 'methods': $cg->addMethods($value); break; } } return $cg; } /** * @param array|string $flags * @return self */ public function setFlags($flags) { return $this; } /** * @param string $flag * @return self */ public function addFlag($flag) { return $this; } /** * @param string $flag * @return self */ public function removeFlag($flag) { return $this; } /** * @param bool $isFinal * @return self */ public function setFinal($isFinal) { return $this; } /** * @param string $extendedClass * @return self */ public function setExtendedClass($extendedClass) { return $this; } /** * @param array $implementedInterfaces * @return self */ public function setImplementedInterfaces(array $implementedInterfaces) { return $this; } /** * @param bool $isAbstract * @return self */ public function setAbstract($isAbstract) { return $this; } } php-zend-code-3.4.1/src/Generator/TraitUsageGenerator.php000066400000000000000000000302431357431215700233330ustar00rootroot00000000000000classGenerator = $classGenerator; } /** * @inheritDoc */ public function addUse($use, $useAlias = null) { $this->removeUse($use); if (! empty($useAlias)) { $use .= ' as ' . $useAlias; } $this->uses[$use] = $use; return $this; } /** * @inheritDoc */ public function getUses() { return array_values($this->uses); } /** * @param string $use * @return bool */ public function hasUse($use) { foreach ($this->uses as $key => $value) { $parts = explode(' ', $value); if ($parts[0] === $use) { return true; } } return false; } /** * @param string $use * @return bool */ public function hasUseAlias($use) { foreach ($this->uses as $key => $value) { $parts = explode(' as ', $value); if ($parts[0] === $use && count($parts) == 2) { return true; } } return false; } /** * Returns the alias of the provided FQCN * * @param string $use * @return string|null */ public function getUseAlias(string $use): ?string { foreach ($this->uses as $key => $value) { $parts = explode(' as ', $key); if ($parts[0] === $use && count($parts) == 2) { return $parts[1]; } } return null; } /** * Returns true if the alias is defined in the use list * * @param string $alias * @return bool */ public function isUseAlias(string $alias): bool { foreach ($this->uses as $key => $value) { $parts = explode(' as ', $key); if (count($parts) === 2 && $parts[1] === $alias) { return true; } } return false; } /** * @param string $use * @return TraitUsageGenerator */ public function removeUse($use) { foreach ($this->uses as $key => $value) { $parts = explode(' ', $value); if ($parts[0] === $use) { unset($this->uses[$value]); } } return $this; } /** * @param string $use * @return TraitUsageGenerator */ public function removeUseAlias($use) { foreach ($this->uses as $key => $value) { $parts = explode(' as ', $value); if ($parts[0] === $use && count($parts) == 2) { unset($this->uses[$value]); } } return $this; } /** * @inheritDoc */ public function addTrait($trait) { $traitName = $trait; if (is_array($trait)) { if (! array_key_exists('traitName', $trait)) { throw new Exception\InvalidArgumentException('Missing required value for traitName'); } $traitName = $trait['traitName']; if (array_key_exists('aliases', $trait)) { foreach ($trait['aliases'] as $alias) { $this->addAlias($alias); } } if (array_key_exists('insteadof', $trait)) { foreach ($trait['insteadof'] as $insteadof) { $this->addTraitOverride($insteadof); } } } if (! $this->hasTrait($traitName)) { $this->traits[] = $traitName; } return $this; } /** * @inheritDoc */ public function addTraits(array $traits) { foreach ($traits as $trait) { $this->addTrait($trait); } return $this; } /** * @inheritDoc */ public function hasTrait($traitName) { return in_array($traitName, $this->traits); } /** * @inheritDoc */ public function getTraits() { return $this->traits; } /** * @inheritDoc */ public function removeTrait($traitName) { $key = array_search($traitName, $this->traits); if (false !== $key) { unset($this->traits[$key]); } return $this; } /** * @inheritDoc */ public function addTraitAlias($method, $alias, $visibility = null) { $traitAndMethod = $method; if (is_array($method)) { if (! array_key_exists('traitName', $method)) { throw new Exception\InvalidArgumentException('Missing required argument "traitName" for $method'); } if (! array_key_exists('method', $method)) { throw new Exception\InvalidArgumentException('Missing required argument "method" for $method'); } $traitAndMethod = $method['traitName'] . '::' . $method['method']; } // Validations if (false === strpos($traitAndMethod, '::')) { throw new Exception\InvalidArgumentException( 'Invalid Format: $method must be in the format of trait::method' ); } if (! is_string($alias)) { throw new Exception\InvalidArgumentException('Invalid Alias: $alias must be a string or array.'); } if ($this->classGenerator->hasMethod($alias)) { throw new Exception\InvalidArgumentException('Invalid Alias: Method name already exists on this class.'); } if (null !== $visibility && $visibility !== ReflectionMethod::IS_PUBLIC && $visibility !== ReflectionMethod::IS_PRIVATE && $visibility !== ReflectionMethod::IS_PROTECTED ) { throw new Exception\InvalidArgumentException( 'Invalid Type: $visibility must of ReflectionMethod::IS_PUBLIC,' . ' ReflectionMethod::IS_PRIVATE or ReflectionMethod::IS_PROTECTED' ); } list($trait, $method) = explode('::', $traitAndMethod); if (! $this->hasTrait($trait)) { throw new Exception\InvalidArgumentException('Invalid trait: Trait does not exists on this class'); } $this->traitAliases[$traitAndMethod] = [ 'alias' => $alias, 'visibility' => $visibility, ]; return $this; } /** * @inheritDoc */ public function getTraitAliases() { return $this->traitAliases; } /** * @inheritDoc */ public function addTraitOverride($method, $traitsToReplace) { if (false === is_array($traitsToReplace)) { $traitsToReplace = [$traitsToReplace]; } $traitAndMethod = $method; if (is_array($method)) { if (! array_key_exists('traitName', $method)) { throw new Exception\InvalidArgumentException('Missing required argument "traitName" for $method'); } if (! array_key_exists('method', $method)) { throw new Exception\InvalidArgumentException('Missing required argument "method" for $method'); } $traitAndMethod = (string) $method['traitName'] . '::' . (string) $method['method']; } // Validations if (false === strpos($traitAndMethod, '::')) { throw new Exception\InvalidArgumentException( 'Invalid Format: $method must be in the format of trait::method' ); } list($trait, $method) = explode('::', $traitAndMethod); if (! $this->hasTrait($trait)) { throw new Exception\InvalidArgumentException('Invalid trait: Trait does not exists on this class'); } if (! array_key_exists($traitAndMethod, $this->traitOverrides)) { $this->traitOverrides[$traitAndMethod] = []; } foreach ($traitsToReplace as $traitToReplace) { if (! is_string($traitToReplace)) { throw new Exception\InvalidArgumentException( 'Invalid Argument: $traitToReplace must be a string or array of strings' ); } if (! in_array($traitToReplace, $this->traitOverrides[$traitAndMethod])) { $this->traitOverrides[$traitAndMethod][] = $traitToReplace; } } return $this; } /** * @inheritDoc */ public function removeTraitOverride($method, $overridesToRemove = null) { if (! array_key_exists($method, $this->traitOverrides)) { return $this; } if (null === $overridesToRemove) { unset($this->traitOverrides[$method]); return $this; } $overridesToRemove = ! is_array($overridesToRemove) ? [$overridesToRemove] : $overridesToRemove; foreach ($overridesToRemove as $traitToRemove) { $key = array_search($traitToRemove, $this->traitOverrides[$method]); if (false !== $key) { unset($this->traitOverrides[$method][$key]); } } return $this; } /** * @inheritDoc */ public function getTraitOverrides() { return $this->traitOverrides; } /** * @inheritDoc */ public function generate() { $output = ''; $indent = $this->getIndentation(); $traits = $this->getTraits(); if (empty($traits)) { return $output; } $output .= $indent . 'use ' . implode(', ', $traits); $aliases = $this->getTraitAliases(); $overrides = $this->getTraitOverrides(); if (empty($aliases) && empty($overrides)) { $output .= ';' . self::LINE_FEED . self::LINE_FEED; return $output; } $output .= ' {' . self::LINE_FEED; foreach ($aliases as $method => $alias) { $visibility = null !== $alias['visibility'] ? current(Reflection::getModifierNames($alias['visibility'])) . ' ' : ''; // validation check if ($this->classGenerator->hasMethod($alias['alias'])) { throw new Exception\RuntimeException(sprintf( 'Generation Error: Aliased method %s already exists on this class', $alias['alias'] )); } $output .= $indent . $indent . $method . ' as ' . $visibility . $alias['alias'] . ';' . self::LINE_FEED; } foreach ($overrides as $method => $insteadofTraits) { foreach ($insteadofTraits as $insteadofTrait) { $output .= $indent . $indent . $method . ' insteadof ' . $insteadofTrait . ';' . self::LINE_FEED; } } $output .= self::LINE_FEED . $indent . '}' . self::LINE_FEED . self::LINE_FEED; return $output; } } php-zend-code-3.4.1/src/Generator/TraitUsageInterface.php000066400000000000000000000105531357431215700233070ustar00rootroot00000000000000:: * Option 2: Array * key: traitName value: trait name * key: method value: method name * * $traitToReplace: * The name of the trait that you wish to supersede. * * This method provides 2 ways for defining the trait method. * Option 1: String of trait to replace * Option 2: Array of strings of traits to replace * @param mixed $method * @param mixed $traitsToReplace */ public function addTraitOverride($method, $traitsToReplace); /** * Remove an override for a given trait::method * * $method: * This method provides 2 ways for defining the trait method. * Option 1: String Format: :: * Option 2: Array * key: traitName value: trait name * key: method value: method name * * $overridesToRemove: * The name of the trait that you wish to remove. * * This method provides 2 ways for defining the trait method. * Option 1: String of trait to replace * Option 2: Array of strings of traits to replace * * @param mixed $method * @param mixed $overridesToRemove * @return self */ public function removeTraitOverride($method, $overridesToRemove = null); /** * Return trait overrides * * @return array */ public function getTraitOverrides(); } php-zend-code-3.4.1/src/Generator/TypeGenerator.php000066400000000000000000000102511357431215700222010ustar00rootroot00000000000000type = $trimmedType; $instance->nullable = $nullable; $instance->isInternalPhpType = $isInternalPhpType; return $instance; } private function __construct() { } /** * {@inheritDoc} */ public function generate() { $nullable = $this->nullable ? '?' : ''; if ($this->isInternalPhpType) { return $nullable . strtolower($this->type); } return $nullable . '\\' . $this->type; } /** * @return string the cleaned type string */ public function __toString() { return ltrim($this->generate(), '?\\'); } /** * @param string $type * * @return bool[]|string[] ordered tuple, first key represents whether the type is nullable, second is the * trimmed string */ private static function trimNullable($type) { if (0 === strpos($type, '?')) { return [true, substr($type, 1)]; } return [false, $type]; } /** * @param string $type * * @return bool[]|string[] ordered tuple, first key represents whether the values was trimmed, second is the * trimmed string */ private static function trimType($type) { if (0 === strpos($type, '\\')) { return [true, substr($type, 1)]; } return [false, $type]; } /** * @param string $type * * @return bool */ private static function isInternalPhpType($type) { return in_array(strtolower($type), self::$internalPhpTypes, true); } } php-zend-code-3.4.1/src/Generator/ValueGenerator.php000066400000000000000000000313401357431215700223360ustar00rootroot00000000000000setValue($value); } if ($type !== self::TYPE_AUTO) { $this->setType($type); } if ($outputMode !== self::OUTPUT_MULTIPLE_LINE) { $this->setOutputMode($outputMode); } if ($constants === null) { $constants = new SplArrayObject(); } elseif (! ($constants instanceof SplArrayObject || $constants instanceof StdlibArrayObject)) { throw new InvalidArgumentException( '$constants must be an instance of ArrayObject or Zend\Stdlib\ArrayObject' ); } $this->constants = $constants; } /** * Init constant list by defined and magic constants */ public function initEnvironmentConstants() { $constants = [ '__DIR__', '__FILE__', '__LINE__', '__CLASS__', '__TRAIT__', '__METHOD__', '__FUNCTION__', '__NAMESPACE__', '::', ]; $constants = array_merge($constants, array_keys(get_defined_constants()), $this->constants->getArrayCopy()); $this->constants->exchangeArray($constants); } /** * Add constant to list * * @param string $constant * * @return $this */ public function addConstant($constant) { $this->constants->append($constant); return $this; } /** * Delete constant from constant list * * @param string $constant * * @return bool */ public function deleteConstant($constant) { if (($index = array_search($constant, $this->constants->getArrayCopy())) !== false) { $this->constants->offsetUnset($index); } return $index !== false; } /** * Return constant list * * @return SplArrayObject|StdlibArrayObject */ public function getConstants() { return $this->constants; } /** * @return bool */ public function isValidConstantType() { if ($this->type === self::TYPE_AUTO) { $type = $this->getAutoDeterminedType($this->value); } else { $type = $this->type; } $validConstantTypes = [ self::TYPE_ARRAY, self::TYPE_ARRAY_LONG, self::TYPE_ARRAY_SHORT, self::TYPE_BOOLEAN, self::TYPE_BOOL, self::TYPE_NUMBER, self::TYPE_INTEGER, self::TYPE_INT, self::TYPE_FLOAT, self::TYPE_DOUBLE, self::TYPE_STRING, self::TYPE_CONSTANT, self::TYPE_NULL, ]; return in_array($type, $validConstantTypes); } /** * @param mixed $value * @return ValueGenerator */ public function setValue($value) { $this->value = $value; return $this; } /** * @return mixed */ public function getValue() { return $this->value; } /** * @param string $type * @return ValueGenerator */ public function setType($type) { $this->type = (string) $type; return $this; } /** * @return string */ public function getType() { return $this->type; } /** * @param int $arrayDepth * @return ValueGenerator */ public function setArrayDepth($arrayDepth) { $this->arrayDepth = (int) $arrayDepth; return $this; } /** * @return int */ public function getArrayDepth() { return $this->arrayDepth; } /** * @param string $type * @return string */ protected function getValidatedType($type) { $types = [ self::TYPE_AUTO, self::TYPE_BOOLEAN, self::TYPE_BOOL, self::TYPE_NUMBER, self::TYPE_INTEGER, self::TYPE_INT, self::TYPE_FLOAT, self::TYPE_DOUBLE, self::TYPE_STRING, self::TYPE_ARRAY, self::TYPE_ARRAY_SHORT, self::TYPE_ARRAY_LONG, self::TYPE_CONSTANT, self::TYPE_NULL, self::TYPE_OBJECT, self::TYPE_OTHER, ]; if (in_array($type, $types)) { return $type; } return self::TYPE_AUTO; } /** * @param mixed $value * @return string */ public function getAutoDeterminedType($value) { switch (gettype($value)) { case 'boolean': return self::TYPE_BOOLEAN; case 'string': foreach ($this->constants as $constant) { if (strpos($value, $constant) !== false) { return self::TYPE_CONSTANT; } } return self::TYPE_STRING; case 'double': case 'float': case 'integer': return self::TYPE_NUMBER; case 'array': return self::TYPE_ARRAY; case 'NULL': return self::TYPE_NULL; case 'object': case 'resource': case 'unknown type': default: return self::TYPE_OTHER; } } /** * @throws Exception\RuntimeException * @return string */ public function generate() { $type = $this->type; if ($type !== self::TYPE_AUTO) { $type = $this->getValidatedType($type); } $value = $this->value; if ($type === self::TYPE_AUTO) { $type = $this->getAutoDeterminedType($value); } $isArrayType = in_array($type, [self::TYPE_ARRAY, self::TYPE_ARRAY_LONG, self::TYPE_ARRAY_SHORT]); if ($isArrayType) { foreach ($value as &$curValue) { if ($curValue instanceof self) { continue; } if (is_array($curValue)) { $newType = $type; } else { $newType = self::TYPE_AUTO; } $curValue = new self($curValue, $newType, self::OUTPUT_MULTIPLE_LINE, $this->getConstants()); $curValue->setIndentation($this->indentation); } } $output = ''; switch ($type) { case self::TYPE_BOOLEAN: case self::TYPE_BOOL: $output .= $value ? 'true' : 'false'; break; case self::TYPE_STRING: $output .= self::escape($value); break; case self::TYPE_NULL: $output .= 'null'; break; case self::TYPE_NUMBER: case self::TYPE_INTEGER: case self::TYPE_INT: case self::TYPE_FLOAT: case self::TYPE_DOUBLE: case self::TYPE_CONSTANT: $output .= $value; break; case self::TYPE_ARRAY: case self::TYPE_ARRAY_LONG: case self::TYPE_ARRAY_SHORT: if ($type === self::TYPE_ARRAY_LONG) { $startArray = 'array('; $endArray = ')'; } else { $startArray = '['; $endArray = ']'; } $output .= $startArray; if ($this->outputMode == self::OUTPUT_MULTIPLE_LINE) { $output .= self::LINE_FEED . str_repeat($this->indentation, $this->arrayDepth + 1); } $outputParts = []; $noKeyIndex = 0; foreach ($value as $n => $v) { /* @var $v ValueGenerator */ $v->setArrayDepth($this->arrayDepth + 1); $partV = $v->generate(); $short = false; if (is_int($n)) { if ($n === $noKeyIndex) { $short = true; $noKeyIndex++; } else { $noKeyIndex = max($n + 1, $noKeyIndex); } } if ($short) { $outputParts[] = $partV; } else { $outputParts[] = (is_int($n) ? $n : self::escape($n)) . ' => ' . $partV; } } $padding = $this->outputMode == self::OUTPUT_MULTIPLE_LINE ? self::LINE_FEED . str_repeat($this->indentation, $this->arrayDepth + 1) : ' '; $output .= implode(',' . $padding, $outputParts); if ($this->outputMode == self::OUTPUT_MULTIPLE_LINE) { if (count($outputParts) > 0) { $output .= ','; } $output .= self::LINE_FEED . str_repeat($this->indentation, $this->arrayDepth); } $output .= $endArray; break; case self::TYPE_OTHER: default: throw new Exception\RuntimeException(sprintf( 'Type "%s" is unknown or cannot be used as property default value.', is_object($value) ? get_class($value) : gettype($value) )); } return $output; } /** * Quotes value for PHP code. * * @param string $input Raw string. * @param bool $quote Whether add surrounding quotes or not. * @return string PHP-ready code. */ public static function escape($input, $quote = true) { $output = addcslashes($input, "\\'"); // adds quoting strings if ($quote) { $output = "'" . $output . "'"; } return $output; } /** * @param string $outputMode * @return ValueGenerator */ public function setOutputMode($outputMode) { $this->outputMode = (string) $outputMode; return $this; } /** * @return string */ public function getOutputMode() { return $this->outputMode; } public function __toString() { return $this->generate(); } } php-zend-code-3.4.1/src/Generic/000077500000000000000000000000001357431215700163275ustar00rootroot00000000000000php-zend-code-3.4.1/src/Generic/Prototype/000077500000000000000000000000001357431215700203345ustar00rootroot00000000000000php-zend-code-3.4.1/src/Generic/Prototype/PrototypeClassFactory.php000066400000000000000000000066741357431215700254050ustar00rootroot00000000000000addPrototype($prototype); } if ($genericPrototype) { $this->setGenericPrototype($genericPrototype); } } /** * @param PrototypeInterface $prototype * @throws Exception\InvalidArgumentException */ public function addPrototype(PrototypeInterface $prototype) { $prototypeName = $this->normalizeName($prototype->getName()); if (isset($this->prototypes[$prototypeName])) { throw new Exception\InvalidArgumentException('A prototype with this name already exists in this manager'); } $this->prototypes[$prototypeName] = $prototype; } /** * @param PrototypeGenericInterface $prototype * @throws Exception\InvalidArgumentException */ public function setGenericPrototype(PrototypeGenericInterface $prototype) { if (isset($this->genericPrototype)) { throw new Exception\InvalidArgumentException('A default prototype is already set'); } $this->genericPrototype = $prototype; } /** * @param string $name * @return string */ protected function normalizeName($name) { return str_replace(['-', '_'], '', $name); } /** * @param string $name * @return bool */ public function hasPrototype($name) { $name = $this->normalizeName($name); return isset($this->prototypes[$name]); } /** * @param string $prototypeName * @return PrototypeInterface * @throws Exception\RuntimeException */ public function getClonedPrototype($prototypeName) { $prototypeName = $this->normalizeName($prototypeName); if (! $this->hasPrototype($prototypeName) && ! isset($this->genericPrototype)) { throw new Exception\RuntimeException('This tag name is not supported by this tag manager'); } if (! $this->hasPrototype($prototypeName)) { $newPrototype = clone $this->genericPrototype; $newPrototype->setName($prototypeName); } else { $newPrototype = clone $this->prototypes[$prototypeName]; } return $newPrototype; } } php-zend-code-3.4.1/src/Generic/Prototype/PrototypeGenericInterface.php000066400000000000000000000007601357431215700261730ustar00rootroot00000000000000setNamespace($namespace); } if ($uses) { $this->setUses($uses); } } /** * @param string $namespace * @return NameInformation */ public function setNamespace($namespace) { $this->namespace = (string) $namespace; return $this; } /** * @return string */ public function getNamespace() { return $this->namespace; } /** * @return bool */ public function hasNamespace() { return $this->namespace !== null; } /** * @param array $uses * @return NameInformation */ public function setUses(array $uses) { $this->uses = []; $this->addUses($uses); return $this; } /** * @param array $uses * @return NameInformation */ public function addUses(array $uses) { foreach ($uses as $use => $as) { if (is_int($use)) { $this->addUse($as); } elseif (is_string($use)) { $this->addUse($use, $as); } } return $this; } /** * @param array|string $use * @param string $as */ public function addUse($use, $as = null) { if (is_array($use) && array_key_exists('use', $use) && array_key_exists('as', $use)) { $uses = $use; $use = $uses['use']; $as = $uses['as']; } $use = trim($use, '\\'); if ($as === null) { $as = trim($use, '\\'); $nsSeparatorPosition = strrpos($as, '\\'); if ($nsSeparatorPosition !== false && $nsSeparatorPosition !== 0 && $nsSeparatorPosition != strlen($as)) { $as = substr($as, $nsSeparatorPosition + 1); } } $this->uses[$use] = $as; } /** * @return array */ public function getUses() { return $this->uses; } /** * @param string $name * @return string */ public function resolveName($name) { if ($this->namespace && ! $this->uses && strlen($name) > 0 && $name[0] != '\\') { return $this->namespace . '\\' . $name; } if (! $this->uses || strlen($name) <= 0 || $name[0] == '\\') { return ltrim($name, '\\'); } if ($this->namespace || $this->uses) { $firstPart = $name; if (($firstPartEnd = strpos($firstPart, '\\')) !== false) { $firstPart = substr($firstPart, 0, $firstPartEnd); } else { $firstPartEnd = strlen($firstPart); } if (($fqns = array_search($firstPart, $this->uses)) !== false) { return substr_replace($name, $fqns, 0, $firstPartEnd); } if ($this->namespace) { return $this->namespace . '\\' . $name; } } return $name; } } php-zend-code-3.4.1/src/Reflection/000077500000000000000000000000001357431215700170455ustar00rootroot00000000000000php-zend-code-3.4.1/src/Reflection/ClassReflection.php000066400000000000000000000162621357431215700226450ustar00rootroot00000000000000getFileName()); return $instance; } /** * Return the classes DocBlock reflection object * * @return DocBlockReflection|false * @throws Exception\ExceptionInterface for missing DocBock or invalid reflection class */ public function getDocBlock() { if (isset($this->docBlock)) { return $this->docBlock; } if ('' == $this->getDocComment()) { return false; } $this->docBlock = new DocBlockReflection($this); return $this->docBlock; } /** * @param AnnotationManager $annotationManager * @return AnnotationCollection|false */ public function getAnnotations(AnnotationManager $annotationManager) { $docComment = $this->getDocComment(); if ($docComment == '') { return false; } if ($this->annotations) { return $this->annotations; } $fileScanner = $this->createFileScanner($this->getFileName()); $nameInformation = $fileScanner->getClassNameInformation($this->getName()); if (! $nameInformation) { return false; } $this->annotations = new AnnotationScanner($annotationManager, $docComment, $nameInformation); return $this->annotations; } /** * Return the start line of the class * * @param bool $includeDocComment * @return int */ public function getStartLine($includeDocComment = false) { if ($includeDocComment && $this->getDocComment() != '') { return $this->getDocBlock()->getStartLine(); } return parent::getStartLine(); } /** * Return the contents of the class * * @param bool $includeDocBlock * @return string */ public function getContents($includeDocBlock = true) { $fileName = $this->getFileName(); if (false === $fileName || ! file_exists($fileName)) { return ''; } $filelines = file($fileName); $startnum = $this->getStartLine($includeDocBlock); $endnum = $this->getEndLine() - $this->getStartLine(); // Ensure we get between the open and close braces $lines = array_slice($filelines, $startnum, $endnum); array_unshift($lines, $filelines[$startnum - 1]); return strstr(implode('', $lines), '{'); } /** * Get all reflection objects of implemented interfaces * * @return ClassReflection[] */ public function getInterfaces() { $phpReflections = parent::getInterfaces(); $zendReflections = []; while ($phpReflections && ($phpReflection = array_shift($phpReflections))) { $instance = new ClassReflection($phpReflection->getName()); $zendReflections[] = $instance; unset($phpReflection); } unset($phpReflections); return $zendReflections; } /** * Return method reflection by name * * @param string $name * @return MethodReflection */ public function getMethod($name) { $method = new MethodReflection($this->getName(), parent::getMethod($name)->getName()); return $method; } /** * Get reflection objects of all methods * * @param int $filter * @return MethodReflection[] */ public function getMethods($filter = -1) { $methods = []; foreach (parent::getMethods($filter) as $method) { $instance = new MethodReflection($this->getName(), $method->getName()); $methods[] = $instance; } return $methods; } /** * Returns an array of reflection classes of traits used by this class. * * @return null|array */ public function getTraits() { $vals = []; $traits = parent::getTraits(); if ($traits === null) { return; } foreach ($traits as $trait) { $vals[] = new ClassReflection($trait->getName()); } return $vals; } /** * Get parent reflection class of reflected class * * @return ClassReflection|bool */ public function getParentClass() { $phpReflection = parent::getParentClass(); if ($phpReflection) { $zendReflection = new ClassReflection($phpReflection->getName()); unset($phpReflection); return $zendReflection; } return false; } /** * Return reflection property of this class by name * * @param string $name * @return PropertyReflection */ public function getProperty($name) { $phpReflection = parent::getProperty($name); $zendReflection = new PropertyReflection($this->getName(), $phpReflection->getName()); unset($phpReflection); return $zendReflection; } /** * Return reflection properties of this class * * @param int $filter * @return PropertyReflection[] */ public function getProperties($filter = -1) { $phpReflections = parent::getProperties($filter); $zendReflections = []; while ($phpReflections && ($phpReflection = array_shift($phpReflections))) { $instance = new PropertyReflection($this->getName(), $phpReflection->getName()); $zendReflections[] = $instance; unset($phpReflection); } unset($phpReflections); return $zendReflections; } /** * @return string */ public function toString() { return parent::__toString(); } /** * @return string */ public function __toString() { return parent::__toString(); } /** * Creates a new FileScanner instance. * * By having this as a separate method it allows the method to be overridden * if a different FileScanner is needed. * * @param string $filename * * @return FileScanner */ protected function createFileScanner($filename) { return new FileScanner($filename); } } php-zend-code-3.4.1/src/Reflection/DocBlock/000077500000000000000000000000001357431215700205255ustar00rootroot00000000000000php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/000077500000000000000000000000001357431215700212405ustar00rootroot00000000000000php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/AuthorTag.php000066400000000000000000000027751357431215700236620ustar00rootroot00000000000000]*)\>)?(.*)$/u', $tagDocblockLine, $match)) { return; } if ($match[1] !== '') { $this->authorName = rtrim($match[1]); } if (isset($match[3]) && $match[3] !== '') { $this->authorEmail = $match[3]; } } /** * @return null|string */ public function getAuthorName() { return $this->authorName; } /** * @return null|string */ public function getAuthorEmail() { return $this->authorEmail; } public function __toString() { return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . "\n"; } } php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/GenericTag.php000066400000000000000000000042271357431215700237660ustar00rootroot00000000000000contentSplitCharacter = $contentSplitCharacter; } /** * @param string $tagDocBlockLine * @return void */ public function initialize($tagDocBlockLine) { $this->parse($tagDocBlockLine); } /** * Get annotation tag name * * @return string */ public function getName() { return $this->name; } /** * @param string $name */ public function setName($name) { $this->name = $name; } /** * @return string */ public function getContent() { return $this->content; } /** * @param int $position * @return string */ public function returnValue($position) { return $this->values[$position]; } /** * Serialize to string * * Required by Reflector * * @todo What should this do? * @return string */ public function __toString() { return 'DocBlock Tag [ * @' . $this->name . ' ]' . "\n"; } /** * @param string $docBlockLine */ protected function parse($docBlockLine) { $this->content = trim($docBlockLine); $this->values = explode($this->contentSplitCharacter, $docBlockLine); } } php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/LicenseTag.php000066400000000000000000000027311357431215700237720ustar00rootroot00000000000000url = trim($match[1]); } if (isset($match[2]) && $match[2] !== '') { $this->licenseName = $match[2]; } } /** * @return null|string */ public function getUrl() { return $this->url; } /** * @return null|string */ public function getLicenseName() { return $this->licenseName; } public function __toString() { return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . "\n"; } } php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/MethodTag.php000066400000000000000000000044521357431215700236320ustar00rootroot00000000000000isStatic = true; } if ($match[2] !== '') { $this->types = explode('|', rtrim($match[2])); } $this->methodName = $match[3]; if ($match[4] !== '') { $this->description = $match[4]; } } /** * Get return value type * * @return null|string * @deprecated 2.0.4 use getTypes instead */ public function getReturnType() { if (empty($this->types)) { return; } return $this->types[0]; } public function getTypes() { return $this->types; } /** * @return string */ public function getMethodName() { return $this->methodName; } /** * @return null|string */ public function getDescription() { return $this->description; } /** * @return bool */ public function isStatic() { return $this->isStatic; } public function __toString() { return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . "\n"; } } php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/ParamTag.php000066400000000000000000000037441357431215700234550ustar00rootroot00000000000000types = explode('|', $matches[1]); if (isset($matches[2])) { $this->variableName = $matches[2]; } if (isset($matches[3])) { $this->description = trim(preg_replace('#\s+#', ' ', $matches[3])); } } /** * Get parameter variable type * * @return string * @deprecated 2.0.4 use getTypes instead */ public function getType() { if (empty($this->types)) { return ''; } return $this->types[0]; } public function getTypes() { return $this->types; } /** * Get parameter name * * @return string */ public function getVariableName() { return $this->variableName; } /** * @return string */ public function getDescription() { return $this->description; } } php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/PhpDocTypedTagInterface.php000066400000000000000000000010211357431215700264030ustar00rootroot00000000000000types = explode('|', rtrim($match[1])); } if ($match[2] !== '') { $this->propertyName = $match[2]; } if ($match[3] !== '') { $this->description = $match[3]; } } /** * @return null|string * @deprecated 2.0.4 use getTypes instead */ public function getType() { if (empty($this->types)) { return; } return $this->types[0]; } public function getTypes() { return $this->types; } /** * @return null|string */ public function getPropertyName() { return $this->propertyName; } /** * @return null|string */ public function getDescription() { return $this->description; } public function __toString() { return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . "\n"; } } php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/ReturnTag.php000066400000000000000000000031531357431215700236660ustar00rootroot00000000000000types = explode('|', $matches[1]); if (isset($matches[2])) { $this->description = trim(preg_replace('#\s+#', ' ', $matches[2])); } } /** * @return string * @deprecated 2.0.4 use getTypes instead */ public function getType() { if (empty($this->types)) { return ''; } return $this->types[0]; } public function getTypes() { return $this->types; } /** * @return string */ public function getDescription() { return $this->description; } } php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/TagInterface.php000066400000000000000000000010741357431215700243070ustar00rootroot00000000000000types = explode('|', $matches[1]); if (isset($matches[2])) { $this->description = $matches[2]; } } /** * Get return variable type * * @return string * @deprecated 2.0.4 use getTypes instead */ public function getType() { return implode('|', $this->getTypes()); } /** * @return array */ public function getTypes() { return $this->types; } /** * @return string */ public function getDescription() { return $this->description; } } php-zend-code-3.4.1/src/Reflection/DocBlock/Tag/VarTag.php000066400000000000000000000033171357431215700231410ustar00rootroot00000000000000types = explode('|', rtrim($match[1])); } if ($match[2] !== '') { $this->variableName = $match[2]; } if ($match[3] !== '') { $this->description = $match[3]; } } /** * {@inheritDoc} */ public function getTypes() : array { return $this->types; } public function getVariableName() : ?string { return $this->variableName; } public function getDescription() : ?string { return $this->description; } public function __toString() : string { return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . PHP_EOL; } } php-zend-code-3.4.1/src/Reflection/DocBlock/TagManager.php000066400000000000000000000026301357431215700232450ustar00rootroot00000000000000addPrototype(new Tag\ParamTag()); $this->addPrototype(new Tag\ReturnTag()); $this->addPrototype(new Tag\MethodTag()); $this->addPrototype(new Tag\PropertyTag()); $this->addPrototype(new Tag\AuthorTag()); $this->addPrototype(new Tag\LicenseTag()); $this->addPrototype(new Tag\ThrowsTag()); $this->addPrototype(new Tag\VarTag()); $this->setGenericPrototype(new Tag\GenericTag()); } /** * @param string $tagName * @param string $content * @return TagInterface */ public function createTag($tagName, $content = null) { /* @var TagInterface $newTag */ $newTag = $this->getClonedPrototype($tagName); if ($content) { $newTag->initialize($content); } return $newTag; } } php-zend-code-3.4.1/src/Reflection/DocBlockReflection.php000066400000000000000000000156421357431215700232610ustar00rootroot00000000000000initializeDefaultTags(); } $this->tagManager = $tagManager; if ($commentOrReflector instanceof Reflector) { $this->reflector = $commentOrReflector; if (! method_exists($commentOrReflector, 'getDocComment')) { throw new Exception\InvalidArgumentException('Reflector must contain method "getDocComment"'); } /* @var MethodReflection $commentOrReflector */ $this->docComment = $commentOrReflector->getDocComment(); // determine line numbers $lineCount = substr_count($this->docComment, "\n"); $this->startLine = $this->reflector->getStartLine() - $lineCount - 1; $this->endLine = $this->reflector->getStartLine() - 1; } elseif (is_string($commentOrReflector)) { $this->docComment = $commentOrReflector; } else { throw new Exception\InvalidArgumentException(sprintf( '%s must have a (string) DocComment or a Reflector in the constructor', get_class($this) )); } if ($this->docComment == '') { throw new Exception\InvalidArgumentException('DocComment cannot be empty'); } $this->reflect(); } /** * Retrieve contents of DocBlock * * @return string */ public function getContents() { $this->reflect(); return $this->cleanDocComment; } /** * Get start line (position) of DocBlock * * @return int */ public function getStartLine() { $this->reflect(); return $this->startLine; } /** * Get last line (position) of DocBlock * * @return int */ public function getEndLine() { $this->reflect(); return $this->endLine; } /** * Get DocBlock short description * * @return string */ public function getShortDescription() { $this->reflect(); return $this->shortDescription; } /** * Get DocBlock long description * * @return string */ public function getLongDescription() { $this->reflect(); return $this->longDescription; } /** * Does the DocBlock contain the given annotation tag? * * @param string $name * @return bool */ public function hasTag($name) { $this->reflect(); foreach ($this->tags as $tag) { if ($tag->getName() == $name) { return true; } } return false; } /** * Retrieve the given DocBlock tag * * @param string $name * @return DocBlockTagInterface|false */ public function getTag($name) { $this->reflect(); foreach ($this->tags as $tag) { if ($tag->getName() == $name) { return $tag; } } return false; } /** * Get all DocBlock annotation tags * * @param string $filter * @return DocBlockTagInterface[] */ public function getTags($filter = null) { $this->reflect(); if ($filter === null || ! is_string($filter)) { return $this->tags; } $returnTags = []; foreach ($this->tags as $tag) { if ($tag->getName() == $filter) { $returnTags[] = $tag; } } return $returnTags; } /** * Parse the DocBlock * * @return void */ protected function reflect() { if ($this->isReflected) { return; } $docComment = preg_replace('#[ ]{0,1}\*/$#', '', $this->docComment); // create a clean docComment $this->cleanDocComment = preg_replace("#[ \t]*(?:/\*\*|\*/|\*)[ ]{0,1}(.*)?#", '$1', $docComment); // @todo should be changed to remove first and last empty line $this->cleanDocComment = ltrim($this->cleanDocComment, "\r\n"); $scanner = new DocBlockScanner($docComment); $this->shortDescription = ltrim($scanner->getShortDescription()); $this->longDescription = ltrim($scanner->getLongDescription()); foreach ($scanner->getTags() as $tag) { $this->tags[] = $this->tagManager->createTag(ltrim($tag['name'], '@'), ltrim($tag['value'])); } $this->isReflected = true; } /** * @return string */ public function toString() { $str = 'DocBlock [ /* DocBlock */ ] {' . "\n\n"; $str .= ' - Tags [' . count($this->tags) . '] {' . "\n"; foreach ($this->tags as $tag) { $str .= ' ' . $tag; } $str .= ' }' . "\n"; $str .= '}' . "\n"; return $str; } /** * Serialize to string * * Required by the Reflector interface * * @return string */ public function __toString() { return $this->toString(); } } php-zend-code-3.4.1/src/Reflection/Exception/000077500000000000000000000000001357431215700210035ustar00rootroot00000000000000php-zend-code-3.4.1/src/Reflection/Exception/BadMethodCallException.php000066400000000000000000000007471357431215700260260ustar00rootroot00000000000000filePath = $fileRealPath; $this->reflect(); } /** * Required by the Reflector interface. * * @todo What should this do? * @return void */ public static function export() { } /** * Return the file name of the reflected file * * @return string */ public function getFileName() { return basename($this->filePath); } /** * Get the start line - Always 1, staying consistent with the Reflection API * * @return int */ public function getStartLine() { return $this->startLine; } /** * Get the end line / number of lines * * @return int */ public function getEndLine() { return $this->endLine; } /** * @return string */ public function getDocComment() { return $this->docComment; } /** * @return DocBlockReflection|false */ public function getDocBlock() { if (! ($docComment = $this->getDocComment())) { return false; } $instance = new DocBlockReflection($docComment); return $instance; } /** * @return string[] */ public function getNamespaces() { return $this->namespaces; } /** * @return null|string */ public function getNamespace() { if (count($this->namespaces) == 0) { return; } return $this->namespaces[0]; } /** * @return array */ public function getUses() { return $this->uses; } /** * Return the reflection classes of the classes found inside this file * * @return ClassReflection[] */ public function getClasses() { $classes = []; foreach ($this->classes as $class) { $classes[] = new ClassReflection($class); } return $classes; } /** * Return the reflection functions of the functions found inside this file * * @return FunctionReflection[] */ public function getFunctions() { $functions = []; foreach ($this->functions as $function) { $functions[] = new FunctionReflection($function); } return $functions; } /** * Retrieve the reflection class of a given class found in this file * * @param null|string $name * @return ClassReflection * @throws Exception\InvalidArgumentException for invalid class name or invalid reflection class */ public function getClass($name = null) { if (null === $name) { reset($this->classes); $selected = current($this->classes); return new ClassReflection($selected); } if (in_array($name, $this->classes)) { return new ClassReflection($name); } throw new Exception\InvalidArgumentException(sprintf( 'Class by name %s not found.', $name )); } /** * Return the full contents of file * * @return string */ public function getContents() { return file_get_contents($this->filePath); } public function toString() { return ''; // @todo } /** * Serialize to string * * Required by the Reflector interface * * @todo What should this serialization look like? * @return string */ public function __toString() { return ''; } /** * This method does the work of "reflecting" the file * * Uses Zend\Code\Scanner\FileScanner to gather file information * * @return void */ protected function reflect() { $scanner = new CachingFileScanner($this->filePath); $this->docComment = $scanner->getDocComment(); $this->requiredFiles = $scanner->getIncludes(); $this->classes = $scanner->getClassNames(); $this->namespaces = $scanner->getNamespaces(); $this->uses = $scanner->getUses(); } /** * Validate / check a file level DocBlock * * @param array $tokens Array of tokenizer tokens * @return void */ protected function checkFileDocBlock($tokens) { foreach ($tokens as $token) { $type = $token[0]; $value = $token[1]; $lineNum = $token[2]; if (($type == T_OPEN_TAG) || ($type == T_WHITESPACE)) { continue; } elseif ($type == T_DOC_COMMENT) { $this->docComment = $value; $this->startLine = $lineNum + substr_count($value, "\n") + 1; return; } else { // Only whitespace is allowed before file DocBlocks return; } } } } php-zend-code-3.4.1/src/Reflection/FunctionReflection.php000066400000000000000000000204711357431215700233620ustar00rootroot00000000000000getDocComment())) { throw new Exception\InvalidArgumentException(sprintf( '%s does not have a DocBlock', $this->getName() )); } $instance = new DocBlockReflection($comment); return $instance; } /** * Get start line (position) of function * * @param bool $includeDocComment * @return int */ public function getStartLine($includeDocComment = false) { if ($includeDocComment) { if ($this->getDocComment() != '') { return $this->getDocBlock()->getStartLine(); } } return parent::getStartLine(); } /** * Get contents of function * * @param bool $includeDocBlock * @return string */ public function getContents($includeDocBlock = true) { $fileName = $this->getFileName(); if (false === $fileName) { return ''; } $startLine = $this->getStartLine(); $endLine = $this->getEndLine(); // eval'd protect if (preg_match('#\((\d+)\) : eval\(\)\'d code$#', $fileName, $matches)) { $fileName = preg_replace('#\(\d+\) : eval\(\)\'d code$#', '', $fileName); $startLine = $endLine = $matches[1]; } $lines = array_slice( file($fileName, FILE_IGNORE_NEW_LINES), $startLine - 1, $endLine - ($startLine - 1), true ); $functionLine = implode("\n", $lines); $content = ''; if ($this->isClosure()) { preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)?\s*\}#s', $functionLine, $matches); if (isset($matches[0])) { $content = $matches[0]; } } else { $name = substr($this->getName(), strrpos($this->getName(), '\\') + 1); preg_match( '#function\s+' . preg_quote($name) . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)?}#', $functionLine, $matches ); if (isset($matches[0])) { $content = $matches[0]; } } $docComment = $this->getDocComment(); return $includeDocBlock && $docComment ? $docComment . "\n" . $content : $content; } /** * Get method prototype * * @param string $format * @return array|string */ public function getPrototype($format = FunctionReflection::PROTOTYPE_AS_ARRAY) { $returnType = 'mixed'; $docBlock = $this->getDocBlock(); if ($docBlock) { $return = $docBlock->getTag('return'); $returnTypes = $return->getTypes(); $returnType = count($returnTypes) > 1 ? implode('|', $returnTypes) : $returnTypes[0]; } $prototype = [ 'namespace' => $this->getNamespaceName(), 'name' => substr($this->getName(), strlen($this->getNamespaceName()) + 1), 'return' => $returnType, 'arguments' => [], ]; $parameters = $this->getParameters(); foreach ($parameters as $parameter) { $prototype['arguments'][$parameter->getName()] = [ 'type' => $parameter->detectType(), 'required' => ! $parameter->isOptional(), 'by_ref' => $parameter->isPassedByReference(), 'default' => $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null, ]; } if ($format == FunctionReflection::PROTOTYPE_AS_STRING) { $line = $prototype['return'] . ' ' . $prototype['name'] . '('; $args = []; foreach ($prototype['arguments'] as $name => $argument) { $argsLine = ($argument['type'] ? $argument['type'] . ' ' : '') . ($argument['by_ref'] ? '&' : '') . '$' . $name; if (! $argument['required']) { $argsLine .= ' = ' . var_export($argument['default'], true); } $args[] = $argsLine; } $line .= implode(', ', $args); $line .= ')'; return $line; } return $prototype; } /** * Get function parameters * * @return ParameterReflection[] */ public function getParameters() { $phpReflections = parent::getParameters(); $zendReflections = []; while ($phpReflections && ($phpReflection = array_shift($phpReflections))) { $instance = new ParameterReflection($this->getName(), $phpReflection->getName()); $zendReflections[] = $instance; unset($phpReflection); } unset($phpReflections); return $zendReflections; } /** * Get return type tag * * @throws Exception\InvalidArgumentException * @return DocBlockReflection */ public function getReturn() { $docBlock = $this->getDocBlock(); if (! $docBlock->hasTag('return')) { throw new Exception\InvalidArgumentException( 'Function does not specify an @return annotation tag; cannot determine return type' ); } $tag = $docBlock->getTag('return'); return new DocBlockReflection('@return ' . $tag->getDescription()); } /** * Get method body * * @return string|false */ public function getBody() { $fileName = $this->getFileName(); if (false === $fileName) { throw new Exception\InvalidArgumentException( 'Cannot determine internals functions body' ); } $startLine = $this->getStartLine(); $endLine = $this->getEndLine(); // eval'd protect if (preg_match('#\((\d+)\) : eval\(\)\'d code$#', $fileName, $matches)) { $fileName = preg_replace('#\(\d+\) : eval\(\)\'d code$#', '', $fileName); $startLine = $endLine = $matches[1]; } $lines = array_slice( file($fileName, FILE_IGNORE_NEW_LINES), $startLine - 1, $endLine - ($startLine - 1), true ); $functionLine = implode("\n", $lines); $body = false; if ($this->isClosure()) { preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)\s*\}#s', $functionLine, $matches); if (isset($matches[2])) { $body = $matches[2]; } } else { $name = substr($this->getName(), strrpos($this->getName(), '\\') + 1); preg_match('#function\s+' . $name . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)}#', $functionLine, $matches); if (isset($matches[1])) { $body = $matches[1]; } } return $body; } /** * @return string */ public function toString() { return $this->__toString(); } /** * Required due to bug in php * * @return string */ public function __toString() { return parent::__toString(); } } php-zend-code-3.4.1/src/Reflection/MethodReflection.php000066400000000000000000000355351357431215700230240ustar00rootroot00000000000000getDocComment()) { return false; } $instance = new DocBlockReflection($this); return $instance; } /** * @param AnnotationManager $annotationManager * @return AnnotationScanner|false */ public function getAnnotations(AnnotationManager $annotationManager) { if (($docComment = $this->getDocComment()) == '') { return false; } if ($this->annotations) { return $this->annotations; } $cachingFileScanner = $this->createFileScanner($this->getFileName()); $nameInformation = $cachingFileScanner->getClassNameInformation($this->getDeclaringClass()->getName()); if (! $nameInformation) { return false; } $this->annotations = new AnnotationScanner($annotationManager, $docComment, $nameInformation); return $this->annotations; } /** * Get start line (position) of method * * @param bool $includeDocComment * @return int */ public function getStartLine($includeDocComment = false) { if ($includeDocComment) { if ($this->getDocComment() != '') { return $this->getDocBlock()->getStartLine(); } } return parent::getStartLine(); } /** * Get reflection of declaring class * * @return ClassReflection */ public function getDeclaringClass() { $phpReflection = parent::getDeclaringClass(); $zendReflection = new ClassReflection($phpReflection->getName()); unset($phpReflection); return $zendReflection; } /** * Get method prototype * * @param string $format * @return array|string */ public function getPrototype($format = MethodReflection::PROTOTYPE_AS_ARRAY) { $returnType = 'mixed'; $docBlock = $this->getDocBlock(); if ($docBlock) { $return = $docBlock->getTag('return'); $returnTypes = $return->getTypes(); $returnType = count($returnTypes) > 1 ? implode('|', $returnTypes) : $returnTypes[0]; } $declaringClass = $this->getDeclaringClass(); $prototype = [ 'namespace' => $declaringClass->getNamespaceName(), 'class' => substr($declaringClass->getName(), strlen($declaringClass->getNamespaceName()) + 1), 'name' => $this->getName(), 'visibility' => $this->isPublic() ? 'public' : ($this->isPrivate() ? 'private' : 'protected'), 'return' => $returnType, 'arguments' => [], ]; $parameters = $this->getParameters(); foreach ($parameters as $parameter) { $prototype['arguments'][$parameter->getName()] = [ 'type' => $parameter->detectType(), 'required' => ! $parameter->isOptional(), 'by_ref' => $parameter->isPassedByReference(), 'default' => $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null, ]; } if ($format == MethodReflection::PROTOTYPE_AS_STRING) { $line = $prototype['visibility'] . ' ' . $prototype['return'] . ' ' . $prototype['name'] . '('; $args = []; foreach ($prototype['arguments'] as $name => $argument) { $argsLine = ($argument['type'] ? $argument['type'] . ' ' : '') . ($argument['by_ref'] ? '&' : '') . '$' . $name; if (! $argument['required']) { $argsLine .= ' = ' . var_export($argument['default'], true); } $args[] = $argsLine; } $line .= implode(', ', $args); $line .= ')'; return $line; } return $prototype; } /** * Get all method parameter reflection objects * * @return ParameterReflection[] */ public function getParameters() { $phpReflections = parent::getParameters(); $zendReflections = []; while ($phpReflections && ($phpReflection = array_shift($phpReflections))) { $instance = new ParameterReflection( [$this->getDeclaringClass()->getName(), $this->getName()], $phpReflection->getName() ); $zendReflections[] = $instance; unset($phpReflection); } unset($phpReflections); return $zendReflections; } /** * Get method contents * * @param bool $includeDocBlock * @return string */ public function getContents($includeDocBlock = true) { $docComment = $this->getDocComment(); $content = $includeDocBlock && ! empty($docComment) ? $docComment . "\n" : ''; $content .= $this->extractMethodContents(); return $content; } /** * Get method body * * @return string */ public function getBody() { return $this->extractMethodContents(true); } /** * Tokenize method string and return concatenated body * * @param bool $bodyOnly * @return string */ protected function extractMethodContents($bodyOnly = false) { $fileName = $this->getFileName(); if ((class_exists($this->class) && false === $fileName) || ! file_exists($fileName)) { return ''; } $lines = array_slice( file($fileName, FILE_IGNORE_NEW_LINES), $this->getStartLine() - 1, $this->getEndLine() - ($this->getStartLine() - 1), true ); $functionLine = implode("\n", $lines); $tokens = token_get_all(' $token) { $tokenType = is_array($token) ? token_name($token[0]) : $token; $tokenValue = is_array($token) ? $token[1] : $token; switch ($tokenType) { case 'T_FINAL': case 'T_ABSTRACT': case 'T_PUBLIC': case 'T_PROTECTED': case 'T_PRIVATE': case 'T_STATIC': case 'T_FUNCTION': // check to see if we have a valid function // then check if we are inside function and have a closure if ($this->isValidFunction($tokens, $key, $this->getName())) { if ($bodyOnly === false) { //if first instance of tokenType grab prefixed whitespace //and append to body if ($capture === false) { $body .= $this->extractPrefixedWhitespace($tokens, $key); } $body .= $tokenValue; } $capture = true; } else { //closure test if ($firstBrace && $tokenType == 'T_FUNCTION') { $body .= $tokenValue; break; } $capture = false; break; } break; case '{': if ($capture === false) { break; } if ($firstBrace === false) { $firstBrace = true; if ($bodyOnly === true) { break; } } $body .= $tokenValue; break; case '}': if ($capture === false) { break; } //check to see if this is the last brace if ($this->isEndingBrace($tokens, $key)) { //capture the end brace if not bodyOnly if ($bodyOnly === false) { $body .= $tokenValue; } break 2; } $body .= $tokenValue; break; default: if ($capture === false) { break; } // if returning body only wait for first brace before capturing if ($bodyOnly === true && $firstBrace !== true) { break; } $body .= $tokenValue; break; } } //remove ending whitespace and return return rtrim($body); } /** * Take current position and find any whitespace * * @param array $haystack * @param int $position * @return string */ protected function extractPrefixedWhitespace($haystack, $position) { $content = ''; $count = count($haystack); if ($position + 1 == $count) { return $content; } for ($i = $position - 1; $i >= 0; $i--) { $tokenType = is_array($haystack[$i]) ? token_name($haystack[$i][0]) : $haystack[$i]; $tokenValue = is_array($haystack[$i]) ? $haystack[$i][1] : $haystack[$i]; //search only for whitespace if ($tokenType == 'T_WHITESPACE') { $content .= $tokenValue; } else { break; } } return $content; } /** * Test for ending brace * * @param array $haystack * @param int $position * @return bool */ protected function isEndingBrace($haystack, $position) { $count = count($haystack); //advance one position $position = $position + 1; if ($position == $count) { return true; } for ($i = $position; $i < $count; $i++) { $tokenType = is_array($haystack[$i]) ? token_name($haystack[$i][0]) : $haystack[$i]; switch ($tokenType) { case 'T_FINAL': case 'T_ABSTRACT': case 'T_PUBLIC': case 'T_PROTECTED': case 'T_PRIVATE': case 'T_STATIC': return true; case 'T_FUNCTION': // If a function is encountered and that function is not a closure // then return true. otherwise the function is a closure, return false if ($this->isValidFunction($haystack, $i)) { return true; } return false; case '}': case ';': case 'T_BREAK': case 'T_CATCH': case 'T_DO': case 'T_ECHO': case 'T_ELSE': case 'T_ELSEIF': case 'T_EVAL': case 'T_EXIT': case 'T_FINALLY': case 'T_FOR': case 'T_FOREACH': case 'T_GOTO': case 'T_IF': case 'T_INCLUDE': case 'T_INCLUDE_ONCE': case 'T_PRINT': case 'T_STRING': case 'T_STRING_VARNAME': case 'T_THROW': case 'T_USE': case 'T_VARIABLE': case 'T_WHILE': case 'T_YIELD': return false; } } } /** * Test to see if current position is valid function or * closure. Returns true if it's a function and NOT a closure * * @param array $haystack * @param int $position * @param string $functionName * @return bool */ protected function isValidFunction($haystack, $position, $functionName = null) { $isValid = false; $count = count($haystack); for ($i = $position + 1; $i < $count; $i++) { $tokenType = is_array($haystack[$i]) ? token_name($haystack[$i][0]) : $haystack[$i]; $tokenValue = is_array($haystack[$i]) ? $haystack[$i][1] : $haystack[$i]; //check for occurrence of ( or if ($tokenType == 'T_STRING') { //check to see if function name is passed, if so validate against that if ($functionName !== null && $tokenValue != $functionName) { $isValid = false; break; } $isValid = true; break; } elseif ($tokenValue == '(') { break; } } return $isValid; } /** * @return string */ public function toString() { return parent::__toString(); } /** * @return string */ public function __toString() { return parent::__toString(); } /** * Creates a new FileScanner instance. * * By having this as a separate method it allows the method to be overridden * if a different FileScanner is needed. * * @param string $filename * * @return CachingFileScanner */ protected function createFileScanner($filename) { return new CachingFileScanner($filename); } } php-zend-code-3.4.1/src/Reflection/ParameterReflection.php000066400000000000000000000061221357431215700235120ustar00rootroot00000000000000getName()); unset($phpReflection); return $zendReflection; } /** * Get class reflection object * * @return null|ClassReflection */ public function getClass() { $phpReflection = parent::getClass(); if ($phpReflection === null) { return null; } $zendReflection = new ClassReflection($phpReflection->getName()); unset($phpReflection); return $zendReflection; } /** * Get declaring function reflection object * * @return FunctionReflection|MethodReflection */ public function getDeclaringFunction() { $phpReflection = parent::getDeclaringFunction(); if ($phpReflection instanceof \ReflectionMethod) { $zendReflection = new MethodReflection($this->getDeclaringClass()->getName(), $phpReflection->getName()); } else { $zendReflection = new FunctionReflection($phpReflection->getName()); } unset($phpReflection); return $zendReflection; } /** * Get parameter type * * @return string|null */ public function detectType() { if (method_exists($this, 'getType') && ($type = $this->getType()) && $type->isBuiltin() ) { return $type->getName(); } // can be dropped when dropping PHP7 support: if ($this->isArray()) { return 'array'; } // can be dropped when dropping PHP7 support: if ($this->isCallable()) { return 'callable'; } if (($class = $this->getClass()) instanceof \ReflectionClass) { return $class->getName(); } $docBlock = $this->getDeclaringFunction()->getDocBlock(); if (! $docBlock instanceof DocBlockReflection) { return null; } $params = $docBlock->getTags('param'); if (isset($params[$this->getPosition()])) { return $params[$this->getPosition()]->getType(); } return null; } /** * @return string */ public function toString() { return parent::__toString(); } /** * @return string */ public function __toString() { return parent::__toString(); } } php-zend-code-3.4.1/src/Reflection/PropertyReflection.php000066400000000000000000000055301357431215700234200ustar00rootroot00000000000000getName()); unset($phpReflection); return $zendReflection; } /** * Get DocBlock comment * * @return string|false False if no DocBlock defined */ public function getDocComment() { return parent::getDocComment(); } /** * @return false|DocBlockReflection */ public function getDocBlock() { if (! ($docComment = $this->getDocComment())) { return false; } $docBlockReflection = new DocBlockReflection($docComment); return $docBlockReflection; } /** * @param AnnotationManager $annotationManager * @return AnnotationScanner|false */ public function getAnnotations(AnnotationManager $annotationManager) { if (null !== $this->annotations) { return $this->annotations; } if (($docComment = $this->getDocComment()) == '') { return false; } $class = $this->getDeclaringClass(); $cachingFileScanner = $this->createFileScanner($class->getFileName()); $nameInformation = $cachingFileScanner->getClassNameInformation($class->getName()); if (! $nameInformation) { return false; } $this->annotations = new AnnotationScanner($annotationManager, $docComment, $nameInformation); return $this->annotations; } /** * @return string */ public function toString() { return $this->__toString(); } /** * Creates a new FileScanner instance. * * By having this as a separate method it allows the method to be overridden * if a different FileScanner is needed. * * @param string $filename * * @return CachingFileScanner */ protected function createFileScanner($filename) { return new CachingFileScanner($filename); } } php-zend-code-3.4.1/src/Reflection/ReflectionInterface.php000066400000000000000000000007411357431215700234730ustar00rootroot00000000000000directories as $scanner) { $classes += $scanner->getClasses(); } if ($returnScannerClass) { foreach ($classes as $index => $class) { $classes[$index] = $this->getClass($class, $returnScannerClass, $returnDerivedScannerClass); } } return $classes; } /** * @param string $class * @return bool */ public function hasClass($class) { foreach ($this->directories as $scanner) { if ($scanner->hasClass($class)) { break; } else { unset($scanner); } } return isset($scanner); } /** * @param string $class * @param bool $returnScannerClass * @param bool $returnDerivedScannerClass * @return ClassScanner|DerivedClassScanner * @throws Exception\RuntimeException */ public function getClass($class, $returnScannerClass = true, $returnDerivedScannerClass = false) { foreach ($this->directories as $scanner) { if ($scanner->hasClass($class)) { break; } else { unset($scanner); } } if (! isset($scanner)) { throw new Exception\RuntimeException('Class by that name was not found.'); } $classScanner = $scanner->getClass($class); return new DerivedClassScanner($classScanner, $this); } /** * @param bool $returnScannerClass */ public function getFunctions($returnScannerClass = false) { $this->scan(); if (! $returnScannerClass) { $functions = []; foreach ($this->infos as $info) { if ($info['type'] == 'function') { $functions[] = $info['name']; } } return $functions; } $scannerClass = new FunctionScanner(); // @todo } } php-zend-code-3.4.1/src/Scanner/AnnotationScanner.php000066400000000000000000000301761357431215700225100ustar00rootroot00000000000000annotationManager = $annotationManager; $this->docComment = $docComment; $this->nameInformation = $nameInformation; $this->scan($this->tokenize()); } /** * @param NameInformation $nameInformation */ public function setNameInformation(NameInformation $nameInformation) { $this->nameInformation = $nameInformation; } /** * @param array $tokens */ protected function scan(array $tokens) { $annotations = []; $annotationIndex = -1; $contentEnd = false; reset($tokens); SCANNER_TOP: $token = current($tokens); switch ($token[0]) { case 'ANNOTATION_CLASS': $contentEnd = false; $annotationIndex++; $class = substr($token[1], 1); $class = $this->nameInformation->resolveName($class); $annotations[$annotationIndex] = [$class, null]; goto SCANNER_CONTINUE; // goto no break needed case 'ANNOTATION_CONTENT_START': $annotations[$annotationIndex][1] = ''; // fall-through case 'ANNOTATION_CONTENT_END': case 'ANNOTATION_CONTENT': case 'ANNOTATION_WHITESPACE': case 'ANNOTATION_NEWLINE': if (! $contentEnd && isset($annotations[$annotationIndex]) && is_string($annotations[$annotationIndex][1]) ) { $annotations[$annotationIndex][1] .= $token[1]; } if ($token[0] === 'ANNOTATION_CONTENT_END') { $contentEnd = true; } goto SCANNER_CONTINUE; // goto no break needed } SCANNER_CONTINUE: if (next($tokens) === false) { goto SCANNER_END; } goto SCANNER_TOP; SCANNER_END: foreach ($annotations as $annotation) { $annotation[] = '@' . $annotation[0] . $annotation[1]; $annotationObject = $this->annotationManager->createAnnotation($annotation); if ($annotationObject) { $this->append($annotationObject); } } } /** * @return array */ protected function tokenize() { static $CONTEXT_DOCBLOCK = 0x01; static $CONTEXT_ASTERISK = 0x02; static $CONTEXT_CLASS = 0x04; static $CONTEXT_CONTENT = 0x08; $context = 0x00; $stream = $this->docComment; $streamIndex = null; $tokens = []; $tokenIndex = null; $currentChar = null; $currentWord = null; $currentLine = null; $annotationParentCount = 0; $MACRO_STREAM_ADVANCE_CHAR = function ($positionsForward = 1) use ( &$stream, &$streamIndex, &$currentChar, &$currentWord, &$currentLine ) { $positionsForward = $positionsForward > 0 ? $positionsForward : 1; $streamIndex = $streamIndex === null ? 0 : $streamIndex + $positionsForward; if (! isset($stream[$streamIndex])) { $currentChar = false; return false; } $currentChar = $stream[$streamIndex]; $matches = []; $currentLine = preg_match('#(.*?)(?:\n|\r\n?)#', $stream, $matches, null, $streamIndex) === 1 ? $matches[1] : substr($stream, $streamIndex); if ($currentChar === ' ') { $currentWord = preg_match('#( +)#', $currentLine, $matches) === 1 ? $matches[1] : $currentLine; } else { $currentWord = ($matches = strpos($currentLine, ' ')) !== false ? substr($currentLine, 0, $matches) : $currentLine; } return $currentChar; }; $MACRO_STREAM_ADVANCE_WORD = function () use (&$currentWord, &$MACRO_STREAM_ADVANCE_CHAR) { return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentWord)); }; $MACRO_STREAM_ADVANCE_LINE = function () use (&$currentLine, &$MACRO_STREAM_ADVANCE_CHAR) { return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentLine)); }; $MACRO_TOKEN_ADVANCE = function () use (&$tokenIndex, &$tokens) { $tokenIndex = $tokenIndex === null ? 0 : $tokenIndex + 1; $tokens[$tokenIndex] = ['ANNOTATION_UNKNOWN', '']; }; $MACRO_TOKEN_SET_TYPE = function ($type) use (&$tokenIndex, &$tokens) { $tokens[$tokenIndex][0] = $type; }; $MACRO_TOKEN_APPEND_CHAR = function () use (&$currentChar, &$tokens, &$tokenIndex) { $tokens[$tokenIndex][1] .= $currentChar; }; $MACRO_TOKEN_APPEND_WORD = function () use (&$currentWord, &$tokens, &$tokenIndex) { $tokens[$tokenIndex][1] .= $currentWord; }; $MACRO_TOKEN_APPEND_LINE = function () use (&$currentLine, &$tokens, &$tokenIndex) { $tokens[$tokenIndex][1] .= $currentLine; }; $MACRO_HAS_CONTEXT = function ($which) use (&$context) { return ($context & $which) === $which; }; $MACRO_STREAM_ADVANCE_CHAR(); $MACRO_TOKEN_ADVANCE(); TOKENIZER_TOP: if ($context === 0x00 && $currentChar === '/' && $currentWord === '/**') { $MACRO_TOKEN_SET_TYPE('ANNOTATION_COMMENTSTART'); $MACRO_TOKEN_APPEND_WORD(); $MACRO_TOKEN_ADVANCE(); $context |= $CONTEXT_DOCBLOCK; $context |= $CONTEXT_ASTERISK; if ($MACRO_STREAM_ADVANCE_WORD() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($MACRO_HAS_CONTEXT($CONTEXT_CLASS)) { if (in_array($currentChar, [' ', '(', "\n", "\r"])) { $context &= ~$CONTEXT_CLASS; $MACRO_TOKEN_ADVANCE(); } else { $MACRO_TOKEN_APPEND_CHAR(); if ($MACRO_STREAM_ADVANCE_CHAR() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } } // Since we don't know what line endings are used in the file, we check for all scenarios. If we find a // carriage return (\r), we check the next character for a line feed (\n). If so we consume it and act as // if the carriage return was a line feed. $lineEnded = $currentChar === "\n"; if ($currentChar === "\r") { $lineEnded = true; $nextChar = $MACRO_STREAM_ADVANCE_CHAR(); if ($nextChar !== "\n") { $streamIndex--; } $currentChar = "\n"; } if ($lineEnded) { $MACRO_TOKEN_SET_TYPE('ANNOTATION_NEWLINE'); $MACRO_TOKEN_APPEND_CHAR(); $MACRO_TOKEN_ADVANCE(); $context &= ~$CONTEXT_ASTERISK; $context &= ~$CONTEXT_CLASS; if ($MACRO_STREAM_ADVANCE_CHAR() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($currentChar === ' ') { $MACRO_TOKEN_SET_TYPE( $MACRO_HAS_CONTEXT($CONTEXT_ASTERISK) ? 'ANNOTATION_WHITESPACE' : 'ANNOTATION_WHITESPACE_INDENT' ); $MACRO_TOKEN_APPEND_WORD(); $MACRO_TOKEN_ADVANCE(); if ($MACRO_STREAM_ADVANCE_WORD() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($MACRO_HAS_CONTEXT($CONTEXT_CONTENT) && $MACRO_HAS_CONTEXT($CONTEXT_ASTERISK)) { $MACRO_TOKEN_SET_TYPE('ANNOTATION_CONTENT'); $annotationParentCount += substr_count($currentWord, '('); $annotationParentCount -= substr_count($currentWord, ')'); if ($annotationParentCount === 0) { $context &= ~$CONTEXT_CONTENT; $MACRO_TOKEN_SET_TYPE('ANNOTATION_CONTENT_END'); } $MACRO_TOKEN_APPEND_WORD(); $MACRO_TOKEN_ADVANCE(); if ($MACRO_STREAM_ADVANCE_WORD() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($currentChar === '(' && $tokens[$tokenIndex - 1][0] === 'ANNOTATION_CLASS') { $context |= $CONTEXT_CONTENT; $annotationParentCount = 1; $MACRO_TOKEN_SET_TYPE('ANNOTATION_CONTENT_START'); $MACRO_TOKEN_APPEND_CHAR(); $MACRO_TOKEN_ADVANCE(); if ($MACRO_STREAM_ADVANCE_CHAR() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($MACRO_HAS_CONTEXT($CONTEXT_DOCBLOCK) && $currentWord === '*/') { $MACRO_TOKEN_SET_TYPE('ANNOTATION_COMMENTEND'); $MACRO_TOKEN_APPEND_WORD(); $MACRO_TOKEN_ADVANCE(); $context &= ~$CONTEXT_DOCBLOCK; if ($MACRO_STREAM_ADVANCE_WORD() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($currentChar === '*') { if ($MACRO_HAS_CONTEXT($CONTEXT_DOCBLOCK) && ($MACRO_HAS_CONTEXT($CONTEXT_ASTERISK))) { $MACRO_TOKEN_SET_TYPE('ANNOTATION_IGNORE'); } else { $MACRO_TOKEN_SET_TYPE('ANNOTATION_ASTERISK'); $context |= $CONTEXT_ASTERISK; } $MACRO_TOKEN_APPEND_CHAR(); $MACRO_TOKEN_ADVANCE(); if ($MACRO_STREAM_ADVANCE_CHAR() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($currentChar === '@') { $MACRO_TOKEN_SET_TYPE('ANNOTATION_CLASS'); $context |= $CONTEXT_CLASS; $MACRO_TOKEN_APPEND_CHAR(); if ($MACRO_STREAM_ADVANCE_CHAR() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } TOKENIZER_CONTINUE: if ($context && $CONTEXT_CONTENT) { $MACRO_TOKEN_APPEND_CHAR(); if ($MACRO_STREAM_ADVANCE_CHAR() === false) { goto TOKENIZER_END; } } else { $MACRO_TOKEN_SET_TYPE('ANNOTATION_IGNORE'); $MACRO_TOKEN_APPEND_LINE(); $MACRO_TOKEN_ADVANCE(); if ($MACRO_STREAM_ADVANCE_LINE() === false) { goto TOKENIZER_END; } } goto TOKENIZER_TOP; TOKENIZER_END: array_pop($tokens); return $tokens; } } php-zend-code-3.4.1/src/Scanner/CachingFileScanner.php000066400000000000000000000070771357431215700225360ustar00rootroot00000000000000fileScanner = static::$cache[$cacheId]; } else { $this->fileScanner = new FileScanner($file, $annotationManager); static::$cache[$cacheId] = $this->fileScanner; } } /** * @return void */ public static function clearCache() { static::$cache = []; } /** * @return AnnotationManager */ public function getAnnotationManager() { return $this->fileScanner->getAnnotationManager(); } /** * @return array|null|string */ public function getFile() { return $this->fileScanner->getFile(); } /** * @return null|string */ public function getDocComment() { return $this->fileScanner->getDocComment(); } /** * @return array */ public function getNamespaces() { return $this->fileScanner->getNamespaces(); } /** * @param null|string $namespace * @return array|null */ public function getUses($namespace = null) { return $this->fileScanner->getUses($namespace); } /** * @return array */ public function getIncludes() { return $this->fileScanner->getIncludes(); } /** * @return array */ public function getClassNames() { return $this->fileScanner->getClassNames(); } /** * @return array */ public function getClasses() { return $this->fileScanner->getClasses(); } /** * @param int|string $className * @return ClassScanner */ public function getClass($className) { return $this->fileScanner->getClass($className); } /** * @param string $className * @return bool|null|NameInformation */ public function getClassNameInformation($className) { return $this->fileScanner->getClassNameInformation($className); } /** * @return array */ public function getFunctionNames() { return $this->fileScanner->getFunctionNames(); } /** * @return array */ public function getFunctions() { return $this->fileScanner->getFunctions(); } } php-zend-code-3.4.1/src/Scanner/ClassScanner.php000066400000000000000000001201541357431215700214370ustar00rootroot00000000000000tokens = $classTokens; $this->nameInformation = $nameInformation; } /** * Get annotations * * @param Annotation\AnnotationManager $annotationManager * @return Annotation\AnnotationCollection */ public function getAnnotations(Annotation\AnnotationManager $annotationManager) { if (($docComment = $this->getDocComment()) == '') { return false; } return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation); } /** * Return documentation comment * * @return null|string */ public function getDocComment() { $this->scan(); return $this->docComment; } /** * Return documentation block * * @return false|DocBlockScanner */ public function getDocBlock() { if (! $docComment = $this->getDocComment()) { return false; } return new DocBlockScanner($docComment); } /** * Return a name of class * * @return null|string */ public function getName() { $this->scan(); return $this->name; } /** * Return short name of class * * @return null|string */ public function getShortName() { $this->scan(); return $this->shortName; } /** * Return number of first line * * @return int|null */ public function getLineStart() { $this->scan(); return $this->lineStart; } /** * Return number of last line * * @return int|null */ public function getLineEnd() { $this->scan(); return $this->lineEnd; } /** * Verify if class is final * * @return bool */ public function isFinal() { $this->scan(); return $this->isFinal; } /** * Verify if class is a trait * * @return bool */ public function isTrait() { $this->scan(); return $this->isTrait; } /** * Verify if class is instantiable * * @return bool */ public function isInstantiable() { $this->scan(); return ! $this->isAbstract && ! $this->isInterface && ! $this->isTrait; } /** * Verify if class is an abstract class * * @return bool */ public function isAbstract() { $this->scan(); return $this->isAbstract; } /** * Verify if class is an interface * * @return bool */ public function isInterface() { $this->scan(); return $this->isInterface; } /** * Verify if class has parent * * @return bool */ public function hasParentClass() { $this->scan(); return $this->parentClass !== null; } /** * Return a name of parent class * * @return null|string */ public function getParentClass() { $this->scan(); return $this->parentClass; } /** * Return a list of interface names * * @return array */ public function getInterfaces() { $this->scan(); return $this->interfaces; } /** * Return a list of constant names * * @return array */ public function getConstantNames() { $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] != 'constant') { continue; } $return[] = $info['name']; } return $return; } /** * Return a list of constants * * @param bool $namesOnly Set false to return instances of ConstantScanner * @return array|ConstantScanner[] */ public function getConstants($namesOnly = true) { if (true === $namesOnly) { trigger_error('Use method getConstantNames() instead', E_USER_DEPRECATED); return $this->getConstantNames(); } $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] != 'constant') { continue; } $return[] = $this->getConstant($info['name']); } return $return; } /** * Return a single constant by given name or index of info * * @param string|int $constantNameOrInfoIndex * @throws Exception\InvalidArgumentException * @return bool|ConstantScanner */ public function getConstant($constantNameOrInfoIndex) { $this->scan(); if (is_int($constantNameOrInfoIndex)) { $info = $this->infos[$constantNameOrInfoIndex]; if ($info['type'] != 'constant') { throw new Exception\InvalidArgumentException('Index of info offset is not about a constant'); } } elseif (is_string($constantNameOrInfoIndex)) { $constantFound = false; foreach ($this->infos as $info) { if ($info['type'] === 'constant' && $info['name'] === $constantNameOrInfoIndex) { $constantFound = true; break; } } if (! $constantFound) { return false; } } else { throw new Exception\InvalidArgumentException( 'Invalid constant name of info index type. Must be of type int or string' ); } if (! isset($info)) { return false; } $p = new ConstantScanner( array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart'] + 1), $this->nameInformation ); $p->setClass($this->name); $p->setScannerClass($this); return $p; } /** * Verify if class has constant * * @param string $name * @return bool */ public function hasConstant($name) { $this->scan(); foreach ($this->infos as $info) { if ($info['type'] === 'constant' && $info['name'] === $name) { return true; } } return false; } /** * Return a list of property names * * @return array */ public function getPropertyNames() { $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] != 'property') { continue; } $return[] = $info['name']; } return $return; } /** * Return a list of properties * * @return PropertyScanner[] */ public function getProperties() { $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] != 'property') { continue; } $return[] = $this->getProperty($info['name']); } return $return; } /** * Return a single property by given name or index of info * * @param string|int $propertyNameOrInfoIndex * @throws Exception\InvalidArgumentException * @return bool|PropertyScanner */ public function getProperty($propertyNameOrInfoIndex) { $this->scan(); if (is_int($propertyNameOrInfoIndex)) { $info = $this->infos[$propertyNameOrInfoIndex]; if ($info['type'] != 'property') { throw new Exception\InvalidArgumentException('Index of info offset is not about a property'); } } elseif (is_string($propertyNameOrInfoIndex)) { $propertyFound = false; foreach ($this->infos as $info) { if ($info['type'] === 'property' && $info['name'] === $propertyNameOrInfoIndex) { $propertyFound = true; break; } } if (! $propertyFound) { return false; } } else { throw new Exception\InvalidArgumentException( 'Invalid property name of info index type. Must be of type int or string' ); } if (! isset($info)) { return false; } $p = new PropertyScanner( array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart'] + 1), $this->nameInformation ); $p->setClass($this->name); $p->setScannerClass($this); return $p; } /** * Verify if class has property * * @param string $name * @return bool */ public function hasProperty($name) { $this->scan(); foreach ($this->infos as $info) { if ($info['type'] === 'property' && $info['name'] === $name) { return true; } } return false; } /** * Retrieve any traits used by the class. * * @return ClassScanner[] */ public function getTraits() { if (! empty($this->traits)) { return $this->traits; } // get list of trait names $traitNames = $this->getTraitNames(); foreach ($traitNames as $traitName) { $r = new ReflectionClass($traitName); if (! $r->isTrait()) { throw new Exception\RuntimeException(sprintf( 'Non-trait class detected as a trait: %s', $traitName )); } $fileName = $r->getFileName(); $file = new FileScanner($fileName); $this->traits[] = $file->getClass($traitName); } return $this->traits; } /** * Retrieve a list of trait names used by this class. * * @return array */ public function getTraitNames() { $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] !== 'use') { continue; } if (is_array($info['use_statements'])) { foreach ($info['use_statements'] as $trait) { $traitName = $trait; if ($this->nameInformation instanceof NameInformation) { $traitName = $this->nameInformation->resolveName($traitName); } $return[] = $traitName; } } } return $return; } /** * Retrieve a list of aliased traits used by the class. * * @return array */ public function getTraitAliases() { $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] !== 'use') { continue; } if (is_array($info['aliases'])) { foreach ($info['aliases'] as $alias) { if (null === $alias || (! empty($alias['type']) && $alias['type'] !== 'as') ) { continue; } // attempt to get fqcn list($trait, $method) = explode('::', $alias['original']); if ($this->nameInformation instanceof NameInformation) { $trait = $this->nameInformation->resolveName($trait); } $return[$alias['alias']] = $trait . '::' . $method; } } } return $return; } /** * Retrieve visibility for a given alias. * * @param mixed $aliasName * @return string */ protected function getVisibilityForAlias($aliasName) { $this->scan(); $return = null; foreach ($this->infos as $info) { if ($info['type'] !== 'use') { continue; } if (is_array($info['aliases'])) { foreach ($info['aliases'] as $alias) { if (null === $alias && (! empty($alias['type']) && $alias['type'] !== 'as') ) { continue; } if ($alias['alias'] === $aliasName) { $return = $alias['visibility']; break 2; } } } } return $return; } /** * Return an array of key = trait to keep, value = trait::method to ignore * * @return array */ protected function getBlockedTraitMethods() { $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] !== 'use') { continue; } if (is_array($info['aliases'])) { foreach ($info['aliases'] as $alias) { if (null === $alias || (! empty($alias['type']) && $alias['type'] !== 'insteadof') ) { continue; } // attempt to get fqcn list($trait, $method) = explode('::', $alias['original']); if ($this->nameInformation instanceof NameInformation) { $trait = $this->nameInformation->resolveName($alias['alias']); } $return[] = $trait . '::' . $method; } } } return $return; } /** * Return a list of method names * * @return array */ public function getMethodNames() { $this->scan(); $methods = $this->getMethods(); $return = []; foreach ($methods as $method) { $return[] = $method->getName(); } return $return; } /** * Return a list of methods * * @return MethodScanner[] */ public function getMethods() { $this->scan(); if (! empty($this->methods)) { return $this->methods; } foreach ($this->infos as $info) { if ($info['type'] !== 'method' && $info['type'] !== 'use') { continue; } // Merge in trait methods if ($info['type'] === 'use') { $traitMethods = []; $traits = $this->getTraits(); $insteadof = $this->getBlockedTraitMethods(); $aliases = $this->getTraitAliases(); foreach ($traits as $trait) { $tempMethods = $trait->getMethods(); foreach ($tempMethods as $tempMethod) { $methodFullName = $trait->getName() . '::' . $tempMethod->getName(); $methodAlias = array_search($methodFullName, $aliases); if (false !== $methodAlias) { // trait::method is aliased // clone the tempMethod as we need to change // the name and possibly the visibility of the // scanned method. // // @todo setName and setVisibility were added to // MethodScanner to accomplish this, may not be the // best option, could use ReflectionClass instead? $newMethod = clone $tempMethod; $newMethod->setName($methodAlias); // if visibility exists, change it on the MethodScanner $visibility = $this->getVisibilityForAlias($methodAlias); if (null !== $visibility) { $newMethod->setVisibility($visibility); } $traitMethods[$methodAlias] = $newMethod; } elseif (in_array($methodFullName, $insteadof)) { // ignore overridden methods continue; } else { if (array_key_exists($tempMethod->getName(), $traitMethods)) { throw new Exception\RuntimeException(sprintf( 'Trait method %s has not been applied because there are' . ' collisions with other trait methods see: (insteadof OR as)', $tempMethod->getName() )); } $traitMethods[$tempMethod->getName()] = $tempMethod; } } } $this->methods = array_merge($this->methods, array_values($traitMethods)); continue; } $m = new MethodScanner( array_slice( $this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart'] + 1 ), $this->nameInformation ); $m->setClass($this->name); $m->setScannerClass($this); $this->methods[] = $m; } return $this->methods; } /** * Return a single method by given name or index of info * * @param string|int $methodNameOrInfoIndex * @throws Exception\InvalidArgumentException * @return MethodScanner */ public function getMethod($methodNameOrInfoIndex) { $this->scan(); if (is_int($methodNameOrInfoIndex)) { $info = $this->infos[$methodNameOrInfoIndex]; if ($info['type'] != 'method') { throw new Exception\InvalidArgumentException('Index of info offset is not about a method'); } $methodNameOrInfoIndex = $info['name']; } $returnMethod = false; $methods = $this->getMethods(); foreach ($methods as $method) { if ($method->getName() === $methodNameOrInfoIndex) { $returnMethod = $method; break; } } return $returnMethod; } /** * Verify if class has method by given name * * @param string $name * @return bool */ public function hasMethod($name) { $this->scan(); return is_object($this->getMethod($name)); } public static function export() { // @todo } public function __toString() { // @todo } /** * Scan tokens * * @return void * @throws Exception\RuntimeException */ protected function scan() { if ($this->isScanned) { return; } if (! $this->tokens) { throw new Exception\RuntimeException('No tokens were provided'); } /** * Variables & Setup */ $tokens = &$this->tokens; // localize $infos = &$this->infos; // localize $tokenIndex = null; $token = null; $tokenType = null; $tokenContent = null; $tokenLine = null; $namespace = null; $infoIndex = 0; $braceCount = 0; /* * MACRO creation */ $MACRO_TOKEN_ADVANCE = function () use ( &$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine ) { static $lastTokenArray = null; $tokenIndex = $tokenIndex === null ? 0 : $tokenIndex + 1; if (! isset($tokens[$tokenIndex])) { $token = false; $tokenContent = false; $tokenType = false; $tokenLine = false; return false; } $token = $tokens[$tokenIndex]; if (is_string($token)) { $tokenType = null; $tokenContent = $token; $tokenLine += substr_count( $lastTokenArray[1] ?? '', "\n" ); // adjust token line by last known newline count } else { $lastTokenArray = $token; [$tokenType, $tokenContent, $tokenLine] = $token; } return $tokenIndex; }; $MACRO_INFO_ADVANCE = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) { $infos[$infoIndex]['tokenEnd'] = $tokenIndex; $infos[$infoIndex]['lineEnd'] = $tokenLine; $infoIndex++; return $infoIndex; }; /** * START FINITE STATE MACHINE FOR SCANNING TOKENS */ // Initialize token $MACRO_TOKEN_ADVANCE(); SCANNER_TOP: switch ($tokenType) { case T_DOC_COMMENT: $this->docComment = $tokenContent; goto SCANNER_CONTINUE; //goto no break needed case T_FINAL: case T_ABSTRACT: case T_CLASS: case T_INTERFACE: case T_TRAIT: // CLASS INFORMATION $classContext = null; $classInterfaceIndex = 0; SCANNER_CLASS_INFO_TOP: if (is_string($tokens[$tokenIndex + 1]) && $tokens[$tokenIndex + 1] === '{') { goto SCANNER_CLASS_INFO_END; } $this->lineStart = $tokenLine; switch ($tokenType) { case T_FINAL: $this->isFinal = true; goto SCANNER_CLASS_INFO_CONTINUE; // goto no break needed case T_ABSTRACT: $this->isAbstract = true; goto SCANNER_CLASS_INFO_CONTINUE; // goto no break needed case T_TRAIT: $this->isTrait = true; $this->shortName = $tokens[$tokenIndex + 2][1]; if ($this->nameInformation && $this->nameInformation->hasNamespace()) { $this->name = $this->nameInformation->getNamespace() . '\\' . $this->shortName; } else { $this->name = $this->shortName; } goto SCANNER_CLASS_INFO_CONTINUE; // goto no break needed case T_INTERFACE: $this->isInterface = true; // fall-through case T_CLASS: $this->shortName = $tokens[$tokenIndex + 2][1]; if ($this->nameInformation && $this->nameInformation->hasNamespace()) { $this->name = $this->nameInformation->getNamespace() . '\\' . $this->shortName; } else { $this->name = $this->shortName; } goto SCANNER_CLASS_INFO_CONTINUE; // goto no break needed case T_NS_SEPARATOR: case T_STRING: switch ($classContext) { case T_EXTENDS: if ($this->isInterface) { $this->shortInterfaces[$classInterfaceIndex] .= $tokenContent; } else { $this->shortParentClass .= $tokenContent; } break; case T_IMPLEMENTS: $this->shortInterfaces[$classInterfaceIndex] .= $tokenContent; break; } goto SCANNER_CLASS_INFO_CONTINUE; // goto no break needed case T_EXTENDS: case T_IMPLEMENTS: $classContext = $tokenType; if (($this->isInterface && $classContext === T_EXTENDS) || $classContext === T_IMPLEMENTS) { $this->shortInterfaces[$classInterfaceIndex] = ''; } elseif (! $this->isInterface && $classContext === T_EXTENDS) { $this->shortParentClass = ''; } goto SCANNER_CLASS_INFO_CONTINUE; // goto no break needed case null: if (($classContext == T_IMPLEMENTS && $tokenContent == ',') || ($classContext == T_EXTENDS && $tokenContent == ',' && $this->isInterface) ) { $classInterfaceIndex++; $this->shortInterfaces[$classInterfaceIndex] = ''; } } SCANNER_CLASS_INFO_CONTINUE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_CLASS_INFO_TOP; SCANNER_CLASS_INFO_END: goto SCANNER_CONTINUE; } if ($tokenType === null && $tokenContent === '{' && $braceCount === 0) { $braceCount++; if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } SCANNER_CLASS_BODY_TOP: if ($braceCount === 0) { goto SCANNER_CLASS_BODY_END; } switch ($tokenType) { case T_CONST: $infos[$infoIndex] = [ 'type' => 'constant', 'tokenStart' => $tokenIndex, 'tokenEnd' => null, 'lineStart' => $tokenLine, 'lineEnd' => null, 'name' => null, 'value' => null, ]; SCANNER_CLASS_BODY_CONST_TOP: if ($tokenContent === ';') { goto SCANNER_CLASS_BODY_CONST_END; } if ($tokenType === T_STRING && null === $infos[$infoIndex]['name']) { $infos[$infoIndex]['name'] = $tokenContent; } SCANNER_CLASS_BODY_CONST_CONTINUE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_CLASS_BODY_CONST_TOP; SCANNER_CLASS_BODY_CONST_END: $MACRO_INFO_ADVANCE(); goto SCANNER_CLASS_BODY_CONTINUE; // goto no break needed case T_USE: // ensure php backwards compatibility if (! defined('T_INSTEADOF')) { define('T_INSTEADOF', 24000); } $infos[$infoIndex] = [ 'type' => 'use', 'tokenStart' => $tokenIndex, 'tokenEnd' => null, 'lineStart' => $tokens[$tokenIndex][2], 'lineEnd' => null, 'name' => $namespace, 'use_statements' => [0 => null], 'aliases' => [0 => null], ]; $isOriginalName = [T_STRING, T_DOUBLE_COLON]; $isAlias = [T_STRING]; $isVisibility = [T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STATIC]; $isAliasType = [T_AS, T_INSTEADOF]; $isValidAlias = array_merge($isOriginalName, $isAlias, $isVisibility, $isAliasType); $useStatementIndex = 0; $aliasStatementIndex = 0; $useAliasContext = false; $useAsContext = false; // start processing with next token if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } SCANNER_USE_TOP: if ($tokenType === null) { if ($tokenContent === '{') { $useStatementIndex = 0; $useAliasContext = true; $infos[$infoIndex]['aliases'][$useStatementIndex] = [ 'original' => null, 'alias' => null, 'visibility' => null, 'type' => 'as', ]; } elseif ($tokenContent === '}') { $useAliasContext = false; goto SCANNER_USE_END; } elseif ($tokenContent === ';') { if ($useAliasContext === true) { $useStatementIndex++; $useAsContext = false; } // only end if we aren't inside braces if (false === $useAliasContext) { goto SCANNER_USE_END; } } elseif ($tokenContent === ',') { $useStatementIndex++; $infos[$infoIndex]['use_statements'][$useStatementIndex] = ''; } } // ANALYZE if ($tokenType !== null) { // use context if (false === $useAliasContext) { if ($tokenType == T_NS_SEPARATOR || $tokenType == T_STRING) { $infos[$infoIndex]['use_statements'][$useStatementIndex] .= $tokenContent; } } else { if (in_array($tokenType, $isValidAlias) && empty($infos[$infoIndex]['aliases'][$useStatementIndex]) ) { $infos[$infoIndex]['aliases'][$useStatementIndex] = [ 'original' => null, 'visibility' => null, 'alias' => null, 'type' => null, ]; } if ($tokenType == T_AS || $tokenType == T_INSTEADOF) { $useAsContext = true; $infos[$infoIndex]['aliases'][$useStatementIndex]['type'] = $tokenType == T_INSTEADOF ? 'insteadof' : 'as'; goto SCANNER_USE_CONTINUE; } // in alias context if ($useAsContext === true && in_array($tokenType, $isAlias)) { $infos[$infoIndex]['aliases'][$useStatementIndex]['alias'] = $tokenContent; } elseif (in_array($tokenType, $isOriginalName)) { $infos[$infoIndex]['aliases'][$useStatementIndex]['original'] .= $tokenContent; } elseif (in_array($tokenType, $isVisibility)) { //add whitespace (will trim later) $infos[$infoIndex]['aliases'][$useStatementIndex]['visibility'] = $tokenType; } } } SCANNER_USE_CONTINUE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_USE_TOP; SCANNER_USE_END: $MACRO_INFO_ADVANCE(); goto SCANNER_CLASS_BODY_CONTINUE; // goto no break needed case T_DOC_COMMENT: case T_PUBLIC: case T_PROTECTED: case T_PRIVATE: case T_ABSTRACT: case T_FINAL: case T_VAR: case T_FUNCTION: $infos[$infoIndex] = [ 'type' => null, 'tokenStart' => $tokenIndex, 'tokenEnd' => null, 'lineStart' => $tokenLine, 'lineEnd' => null, 'name' => null, ]; $memberContext = null; $methodBodyStarted = false; SCANNER_CLASS_BODY_MEMBER_TOP: if ($memberContext === 'method') { switch ($tokenContent) { case '{': $methodBodyStarted = true; $braceCount++; goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; // goto no break needed case '}': $braceCount--; goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; // goto no break needed case ';': $infos[$infoIndex]['tokenEnd'] = $tokenIndex; goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; // goto no break needed } } if ($memberContext !== null) { if (($memberContext === 'property' && $tokenContent === ';') || ($memberContext === 'method' && $methodBodyStarted && $braceCount === 1) || ($memberContext === 'method' && $this->isInterface && $tokenContent === ';') ) { goto SCANNER_CLASS_BODY_MEMBER_END; } } switch ($tokenType) { case T_CONST: $memberContext = 'constant'; $infos[$infoIndex]['type'] = 'constant'; goto SCANNER_CLASS_BODY_CONST_CONTINUE; //goto no break needed case T_VARIABLE: if ($memberContext === null) { $memberContext = 'property'; $infos[$infoIndex]['type'] = 'property'; $infos[$infoIndex]['name'] = ltrim($tokenContent, '$'); } goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; // goto no break needed case T_FUNCTION: $memberContext = 'method'; $infos[$infoIndex]['type'] = 'method'; goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; // goto no break needed case T_STRING: if ($memberContext === 'method' && null === $infos[$infoIndex]['name']) { $infos[$infoIndex]['name'] = $tokenContent; } goto SCANNER_CLASS_BODY_MEMBER_CONTINUE; // goto no break needed } SCANNER_CLASS_BODY_MEMBER_CONTINUE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_CLASS_BODY_MEMBER_TOP; SCANNER_CLASS_BODY_MEMBER_END: $memberContext = null; $MACRO_INFO_ADVANCE(); goto SCANNER_CLASS_BODY_CONTINUE; // goto no break needed case null: // no type, is a string switch ($tokenContent) { case '{': $braceCount++; goto SCANNER_CLASS_BODY_CONTINUE; // goto no break needed case '}': $braceCount--; goto SCANNER_CLASS_BODY_CONTINUE; // goto no break needed } } SCANNER_CLASS_BODY_CONTINUE: if ($braceCount === 0 || $MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_CONTINUE; } goto SCANNER_CLASS_BODY_TOP; SCANNER_CLASS_BODY_END: goto SCANNER_CONTINUE; } SCANNER_CONTINUE: if ($tokenContent === '}') { $this->lineEnd = $tokenLine; } if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_TOP; SCANNER_END: // process short names if ($this->nameInformation) { if ($this->shortParentClass) { $this->parentClass = $this->nameInformation->resolveName($this->shortParentClass); } if ($this->shortInterfaces) { foreach ($this->shortInterfaces as $siIndex => $si) { $this->interfaces[$siIndex] = $this->nameInformation->resolveName($si); } } } else { $this->parentClass = $this->shortParentClass; $this->interfaces = $this->shortInterfaces; } $this->isScanned = true; } } php-zend-code-3.4.1/src/Scanner/ConstantScanner.php000066400000000000000000000127631357431215700221710ustar00rootroot00000000000000tokens = $constantTokens; $this->nameInformation = $nameInformation; } /** * @param string $class */ public function setClass($class) { $this->class = $class; } /** * @param ClassScanner $scannerClass */ public function setScannerClass(ClassScanner $scannerClass) { $this->scannerClass = $scannerClass; } /** * @return ClassScanner */ public function getClassScanner() { return $this->scannerClass; } /** * @return string */ public function getName() { $this->scan(); return $this->name; } /** * @return string */ public function getValue() { $this->scan(); return $this->value; } /** * @return string */ public function getDocComment() { $this->scan(); return $this->docComment; } /** * @param Annotation\AnnotationManager $annotationManager * @return AnnotationScanner */ public function getAnnotations(Annotation\AnnotationManager $annotationManager) { if (($docComment = $this->getDocComment()) == '') { return false; } return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation); } /** * @return string */ public function __toString() { $this->scan(); return var_export($this, true); } /** * Scan tokens * * @throws Exception\RuntimeException */ protected function scan() { if ($this->isScanned) { return; } if (! $this->tokens) { throw new Exception\RuntimeException('No tokens were provided'); } /** * Variables & Setup */ $tokens = &$this->tokens; reset($tokens); SCANNER_TOP: $token = current($tokens); if (! is_string($token)) { list($tokenType, $tokenContent, $tokenLine) = $token; switch ($tokenType) { case T_DOC_COMMENT: if ($this->docComment === null && $this->name === null) { $this->docComment = $tokenContent; } goto SCANNER_CONTINUE; // fall-through case T_STRING: $string = is_string($token) ? $token : $tokenContent; if (null === $this->name) { $this->name = $string; } else { if ('self' == strtolower($string)) { list($tokenNextType, $tokenNextContent, $tokenNextLine) = next($tokens); if ('::' == $tokenNextContent) { list($tokenNextType, $tokenNextContent, $tokenNextLine) = next($tokens); if ($this->getClassScanner()->getConstant($tokenNextContent)) { $this->value = $this->getClassScanner()->getConstant($tokenNextContent)->getValue(); } } } } goto SCANNER_CONTINUE; // fall-through case T_CONSTANT_ENCAPSED_STRING: case T_DNUMBER: case T_LNUMBER: $string = is_string($token) ? $token : $tokenContent; if (0 === strpos($string, '"') || 0 === strpos($string, "'")) { $this->value = substr($string, 1, -1); // Remove quotes } else { $this->value = $string; } goto SCANNER_CONTINUE; // fall-trough default: goto SCANNER_CONTINUE; } } SCANNER_CONTINUE: if (next($this->tokens) === false) { goto SCANNER_END; } goto SCANNER_TOP; SCANNER_END: $this->isScanned = true; } } php-zend-code-3.4.1/src/Scanner/DerivedClassScanner.php000066400000000000000000000240511357431215700227410ustar00rootroot00000000000000classScanner = $classScanner; $this->directoryScanner = $directoryScanner; $currentScannerClass = $classScanner; while ($currentScannerClass && $currentScannerClass->hasParentClass()) { $currentParentClassName = $currentScannerClass->getParentClass(); if ($directoryScanner->hasClass($currentParentClassName)) { $currentParentClass = $directoryScanner->getClass($currentParentClassName); $this->parentClassScanners[$currentParentClassName] = $currentParentClass; $currentScannerClass = $currentParentClass; } else { $currentScannerClass = false; } } foreach ($interfaces = $this->classScanner->getInterfaces() as $iName) { if ($directoryScanner->hasClass($iName)) { $this->interfaceClassScanners[$iName] = $directoryScanner->getClass($iName); } } } /** * @return null|string */ public function getName() { return $this->classScanner->getName(); } /** * @return null|string */ public function getShortName() { return $this->classScanner->getShortName(); } /** * @return bool */ public function isInstantiable() { return $this->classScanner->isInstantiable(); } /** * @return bool */ public function isFinal() { return $this->classScanner->isFinal(); } /** * @return bool */ public function isAbstract() { return $this->classScanner->isAbstract(); } /** * @return bool */ public function isInterface() { return $this->classScanner->isInterface(); } /** * @return array */ public function getParentClasses() { return array_keys($this->parentClassScanners); } /** * @return bool */ public function hasParentClass() { return $this->classScanner->getParentClass() !== null; } /** * @return null|string */ public function getParentClass() { return $this->classScanner->getParentClass(); } /** * @param bool $returnClassScanners * @return array */ public function getInterfaces($returnClassScanners = false) { if ($returnClassScanners) { return $this->interfaceClassScanners; } $interfaces = $this->classScanner->getInterfaces(); foreach ($this->parentClassScanners as $pClassScanner) { $interfaces = array_merge($interfaces, $pClassScanner->getInterfaces()); } return $interfaces; } /** * Return a list of constant names * * @return array */ public function getConstantNames() { $constants = $this->classScanner->getConstantNames(); foreach ($this->parentClassScanners as $pClassScanner) { $constants = array_merge($constants, $pClassScanner->getConstantNames()); } return $constants; } /** * Return a list of constants * * @param bool $namesOnly Set false to return instances of ConstantScanner * @return array|ConstantScanner[] */ public function getConstants($namesOnly = true) { if (true === $namesOnly) { trigger_error('Use method getConstantNames() instead', E_USER_DEPRECATED); return $this->getConstantNames(); } $constants = $this->classScanner->getConstants(); foreach ($this->parentClassScanners as $pClassScanner) { $constants = array_merge($constants, $pClassScanner->getConstants($namesOnly)); } return $constants; } /** * Return a single constant by given name or index of info * * @param string|int $constantNameOrInfoIndex * @throws Exception\InvalidArgumentException * @return bool|ConstantScanner */ public function getConstant($constantNameOrInfoIndex) { if ($this->classScanner->hasConstant($constantNameOrInfoIndex)) { return $this->classScanner->getConstant($constantNameOrInfoIndex); } foreach ($this->parentClassScanners as $pClassScanner) { if ($pClassScanner->hasConstant($constantNameOrInfoIndex)) { return $pClassScanner->getConstant($constantNameOrInfoIndex); } } throw new Exception\InvalidArgumentException(sprintf( 'Constant %s not found in %s', $constantNameOrInfoIndex, $this->classScanner->getName() )); } /** * Verify if class or parent class has constant * * @param string $name * @return bool */ public function hasConstant($name) { if ($this->classScanner->hasConstant($name)) { return true; } foreach ($this->parentClassScanners as $pClassScanner) { if ($pClassScanner->hasConstant($name)) { return true; } } return false; } /** * Return a list of property names * * @return array */ public function getPropertyNames() { $properties = $this->classScanner->getPropertyNames(); foreach ($this->parentClassScanners as $pClassScanner) { $properties = array_merge($properties, $pClassScanner->getPropertyNames()); } return $properties; } /** * @param bool $returnScannerProperty * @return array */ public function getProperties($returnScannerProperty = false) { $properties = $this->classScanner->getProperties($returnScannerProperty); foreach ($this->parentClassScanners as $pClassScanner) { $properties = array_merge($properties, $pClassScanner->getProperties($returnScannerProperty)); } return $properties; } /** * Return a single property by given name or index of info * * @param string|int $propertyNameOrInfoIndex * @throws Exception\InvalidArgumentException * @return bool|PropertyScanner */ public function getProperty($propertyNameOrInfoIndex) { if ($this->classScanner->hasProperty($propertyNameOrInfoIndex)) { return $this->classScanner->getProperty($propertyNameOrInfoIndex); } foreach ($this->parentClassScanners as $pClassScanner) { if ($pClassScanner->hasProperty($propertyNameOrInfoIndex)) { return $pClassScanner->getProperty($propertyNameOrInfoIndex); } } throw new Exception\InvalidArgumentException(sprintf( 'Property %s not found in %s', $propertyNameOrInfoIndex, $this->classScanner->getName() )); } /** * Verify if class or parent class has property * * @param string $name * @return bool */ public function hasProperty($name) { if ($this->classScanner->hasProperty($name)) { return true; } foreach ($this->parentClassScanners as $pClassScanner) { if ($pClassScanner->hasProperty($name)) { return true; } } return false; } /** * @return array */ public function getMethodNames() { $methods = $this->classScanner->getMethodNames(); foreach ($this->parentClassScanners as $pClassScanner) { $methods = array_merge($methods, $pClassScanner->getMethodNames()); } return $methods; } /** * @return MethodScanner[] */ public function getMethods() { $methods = $this->classScanner->getMethods(); foreach ($this->parentClassScanners as $pClassScanner) { $methods = array_merge($methods, $pClassScanner->getMethods()); } return $methods; } /** * @param int|string $methodNameOrInfoIndex * @return MethodScanner * @throws Exception\InvalidArgumentException */ public function getMethod($methodNameOrInfoIndex) { if ($this->classScanner->hasMethod($methodNameOrInfoIndex)) { return $this->classScanner->getMethod($methodNameOrInfoIndex); } foreach ($this->parentClassScanners as $pClassScanner) { if ($pClassScanner->hasMethod($methodNameOrInfoIndex)) { return $pClassScanner->getMethod($methodNameOrInfoIndex); } } throw new Exception\InvalidArgumentException(sprintf( 'Method %s not found in %s', $methodNameOrInfoIndex, $this->classScanner->getName() )); } /** * Verify if class or parent class has method by given name * * @param string $name * @return bool */ public function hasMethod($name) { if ($this->classScanner->hasMethod($name)) { return true; } foreach ($this->parentClassScanners as $pClassScanner) { if ($pClassScanner->hasMethod($name)) { return true; } } return false; } } php-zend-code-3.4.1/src/Scanner/DirectoryScanner.php000066400000000000000000000160051357431215700223350ustar00rootroot00000000000000addDirectory($directory); } elseif (is_array($directory)) { foreach ($directory as $d) { $this->addDirectory($d); } } } } /** * @param DirectoryScanner|string $directory * @return void * @throws Exception\InvalidArgumentException */ public function addDirectory($directory) { if ($directory instanceof DirectoryScanner) { $this->directories[] = $directory; } elseif (is_string($directory)) { $realDir = realpath($directory); if (! $realDir || ! is_dir($realDir)) { throw new Exception\InvalidArgumentException(sprintf( 'Directory "%s" does not exist', $realDir )); } $this->directories[] = $realDir; } else { throw new Exception\InvalidArgumentException( 'The argument provided was neither a DirectoryScanner or directory path' ); } } /** * @param DirectoryScanner $directoryScanner * @return void */ public function addDirectoryScanner(DirectoryScanner $directoryScanner) { $this->addDirectory($directoryScanner); } /** * @param FileScanner $fileScanner * @return void */ public function addFileScanner(FileScanner $fileScanner) { $this->fileScanners[] = $fileScanner; } /** * @return void */ protected function scan() { if ($this->isScanned) { return; } // iterate directories creating file scanners foreach ($this->directories as $directory) { if ($directory instanceof DirectoryScanner) { $directory->scan(); if ($directory->fileScanners) { $this->fileScanners = array_merge($this->fileScanners, $directory->fileScanners); } } else { $rdi = new RecursiveDirectoryIterator($directory); foreach (new RecursiveIteratorIterator($rdi) as $item) { if ($item->isFile() && pathinfo($item->getRealPath(), PATHINFO_EXTENSION) == 'php') { $this->fileScanners[] = new FileScanner($item->getRealPath()); } } } } $this->isScanned = true; } /** * @todo implement method */ public function getNamespaces() { // @todo } /** * @param bool $returnFileScanners * @return array */ public function getFiles($returnFileScanners = false) { $this->scan(); $return = []; foreach ($this->fileScanners as $fileScanner) { $return[] = $returnFileScanners ? $fileScanner : $fileScanner->getFile(); } return $return; } /** * @return array */ public function getClassNames() { $this->scan(); if ($this->classToFileScanner === null) { $this->createClassToFileScannerCache(); } return array_keys($this->classToFileScanner); } /** * @param bool $returnDerivedScannerClass * @return array */ public function getClasses($returnDerivedScannerClass = false) { $this->scan(); if ($this->classToFileScanner === null) { $this->createClassToFileScannerCache(); } $returnClasses = []; foreach ($this->classToFileScanner as $className => $fsIndex) { $classScanner = $this->fileScanners[$fsIndex]->getClass($className); if ($returnDerivedScannerClass) { $classScanner = new DerivedClassScanner($classScanner, $this); } $returnClasses[] = $classScanner; } return $returnClasses; } /** * @param string $class * @return bool */ public function hasClass($class) { $this->scan(); if ($this->classToFileScanner === null) { $this->createClassToFileScannerCache(); } return isset($this->classToFileScanner[$class]); } /** * @param string $class * @param bool $returnDerivedScannerClass * @return ClassScanner|DerivedClassScanner * @throws Exception\InvalidArgumentException */ public function getClass($class, $returnDerivedScannerClass = false) { $this->scan(); if ($this->classToFileScanner === null) { $this->createClassToFileScannerCache(); } if (! isset($this->classToFileScanner[$class])) { throw new Exception\InvalidArgumentException('Class not found.'); } /** @var FileScanner $fs */ $fs = $this->fileScanners[$this->classToFileScanner[$class]]; $returnClass = $fs->getClass($class); if ($returnClass instanceof ClassScanner && $returnDerivedScannerClass) { return new DerivedClassScanner($returnClass, $this); } return $returnClass; } /** * Create class to file scanner cache * * @return void */ protected function createClassToFileScannerCache() { if ($this->classToFileScanner !== null) { return; } $this->classToFileScanner = []; /** @var FileScanner $fileScanner */ foreach ($this->fileScanners as $fsIndex => $fileScanner) { $fsClasses = $fileScanner->getClassNames(); foreach ($fsClasses as $fsClassName) { $this->classToFileScanner[$fsClassName] = $fsIndex; } } } /** * Export * * @todo implement method */ public static function export() { // @todo } /** * __ToString * * @todo implement method */ public function __toString() { // @todo } } php-zend-code-3.4.1/src/Scanner/DocBlockScanner.php000066400000000000000000000241721357431215700220550ustar00rootroot00000000000000docComment = $docComment; $this->nameInformation = $nameInformation; } /** * @return string */ public function getShortDescription() { $this->scan(); return $this->shortDescription; } /** * @return string */ public function getLongDescription() { $this->scan(); return $this->longDescription; } /** * @return array */ public function getTags() { $this->scan(); return $this->tags; } /** * @return array */ public function getAnnotations() { $this->scan(); return $this->annotations; } /** * @return void */ protected function scan() { if ($this->isScanned) { return; } $mode = 1; $tokens = $this->tokenize(); $tagIndex = null; reset($tokens); SCANNER_TOP: $token = current($tokens); switch ($token[0]) { case 'DOCBLOCK_NEWLINE': if ($this->shortDescription != '' && $tagIndex === null) { $mode = 2; } else { $this->longDescription .= $token[1]; } goto SCANNER_CONTINUE; //goto no break needed case 'DOCBLOCK_WHITESPACE': case 'DOCBLOCK_TEXT': if ($tagIndex !== null) { $this->tags[$tagIndex]['value'] .= $this->tags[$tagIndex]['value'] == '' ? $token[1] : ' ' . $token[1]; goto SCANNER_CONTINUE; } elseif ($mode <= 2) { if ($mode == 1) { $this->shortDescription .= $token[1]; } else { $this->longDescription .= $token[1]; } goto SCANNER_CONTINUE; } //gotos no break needed case 'DOCBLOCK_TAG': array_push($this->tags, [ 'name' => $token[1], 'value' => '', ]); end($this->tags); $tagIndex = key($this->tags); $mode = 3; goto SCANNER_CONTINUE; //goto no break needed case 'DOCBLOCK_COMMENTEND': goto SCANNER_END; } SCANNER_CONTINUE: if (next($tokens) === false) { goto SCANNER_END; } goto SCANNER_TOP; SCANNER_END: $this->shortDescription = trim($this->shortDescription); $this->longDescription = trim($this->longDescription); $this->isScanned = true; } /** * @return array */ protected function tokenize() { static $CONTEXT_INSIDE_DOCBLOCK = 0x01; static $CONTEXT_INSIDE_ASTERISK = 0x02; $context = 0x00; $stream = $this->docComment; $streamIndex = null; $tokens = []; $tokenIndex = null; $currentChar = null; $currentWord = null; $currentLine = null; $MACRO_STREAM_ADVANCE_CHAR = function ($positionsForward = 1) use ( &$stream, &$streamIndex, &$currentChar, &$currentWord, &$currentLine ) { $positionsForward = $positionsForward > 0 ? $positionsForward : 1; $streamIndex = $streamIndex === null ? 0 : $streamIndex + $positionsForward; if (! isset($stream[$streamIndex])) { $currentChar = false; return false; } $currentChar = $stream[$streamIndex]; $matches = []; $currentLine = preg_match('#(.*?)\r?\n#', $stream, $matches, null, $streamIndex) === 1 ? $matches[1] : substr($stream, $streamIndex); if ($currentChar === ' ') { $currentWord = preg_match('#( +)#', $currentLine, $matches) === 1 ? $matches[1] : $currentLine; } else { $currentWord = ($matches = strpos($currentLine, ' ')) !== false ? substr($currentLine, 0, $matches) : $currentLine; } return $currentChar; }; $MACRO_STREAM_ADVANCE_WORD = function () use (&$currentWord, &$MACRO_STREAM_ADVANCE_CHAR) { return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentWord)); }; $MACRO_STREAM_ADVANCE_LINE = function () use (&$currentLine, &$MACRO_STREAM_ADVANCE_CHAR) { return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentLine)); }; $MACRO_TOKEN_ADVANCE = function () use (&$tokenIndex, &$tokens) { $tokenIndex = $tokenIndex === null ? 0 : $tokenIndex + 1; $tokens[$tokenIndex] = ['DOCBLOCK_UNKNOWN', '']; }; $MACRO_TOKEN_SET_TYPE = function ($type) use (&$tokenIndex, &$tokens) { $tokens[$tokenIndex][0] = $type; }; $MACRO_TOKEN_APPEND_CHAR = function () use (&$currentChar, &$tokens, &$tokenIndex) { $tokens[$tokenIndex][1] .= $currentChar; }; $MACRO_TOKEN_APPEND_WORD = function () use (&$currentWord, &$tokens, &$tokenIndex) { $tokens[$tokenIndex][1] .= $currentWord; }; $MACRO_TOKEN_APPEND_WORD_PARTIAL = function ($length) use (&$currentWord, &$tokens, &$tokenIndex) { $tokens[$tokenIndex][1] .= substr($currentWord, 0, $length); }; $MACRO_TOKEN_APPEND_LINE = function () use (&$currentLine, &$tokens, &$tokenIndex) { $tokens[$tokenIndex][1] .= $currentLine; }; $MACRO_STREAM_ADVANCE_CHAR(); $MACRO_TOKEN_ADVANCE(); TOKENIZER_TOP: if ($context === 0x00 && $currentChar === '/' && $currentWord === '/**') { $MACRO_TOKEN_SET_TYPE('DOCBLOCK_COMMENTSTART'); $MACRO_TOKEN_APPEND_WORD(); $MACRO_TOKEN_ADVANCE(); $context |= $CONTEXT_INSIDE_DOCBLOCK; $context |= $CONTEXT_INSIDE_ASTERISK; if ($MACRO_STREAM_ADVANCE_WORD() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($context & $CONTEXT_INSIDE_DOCBLOCK && $currentWord === '*/') { $MACRO_TOKEN_SET_TYPE('DOCBLOCK_COMMENTEND'); $MACRO_TOKEN_APPEND_WORD(); $MACRO_TOKEN_ADVANCE(); $context &= ~$CONTEXT_INSIDE_DOCBLOCK; if ($MACRO_STREAM_ADVANCE_WORD() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($currentChar === ' ' || $currentChar === "\t") { $MACRO_TOKEN_SET_TYPE( $context & $CONTEXT_INSIDE_ASTERISK ? 'DOCBLOCK_WHITESPACE' : 'DOCBLOCK_WHITESPACE_INDENT' ); $MACRO_TOKEN_APPEND_WORD(); $MACRO_TOKEN_ADVANCE(); if ($MACRO_STREAM_ADVANCE_WORD() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($currentChar === '*') { if (($context & $CONTEXT_INSIDE_DOCBLOCK) && ($context & $CONTEXT_INSIDE_ASTERISK)) { $MACRO_TOKEN_SET_TYPE('DOCBLOCK_TEXT'); } else { $MACRO_TOKEN_SET_TYPE('DOCBLOCK_ASTERISK'); $context |= $CONTEXT_INSIDE_ASTERISK; } $MACRO_TOKEN_APPEND_CHAR(); $MACRO_TOKEN_ADVANCE(); if ($MACRO_STREAM_ADVANCE_CHAR() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($currentChar === '@') { $MACRO_TOKEN_SET_TYPE('DOCBLOCK_TAG'); $MACRO_TOKEN_APPEND_WORD(); $MACRO_TOKEN_ADVANCE(); if ($MACRO_STREAM_ADVANCE_WORD() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } if ($currentChar === "\n") { $MACRO_TOKEN_SET_TYPE('DOCBLOCK_NEWLINE'); $MACRO_TOKEN_APPEND_CHAR(); $MACRO_TOKEN_ADVANCE(); $context &= ~$CONTEXT_INSIDE_ASTERISK; if ($MACRO_STREAM_ADVANCE_CHAR() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; } $MACRO_TOKEN_SET_TYPE('DOCBLOCK_TEXT'); $MACRO_TOKEN_APPEND_LINE(); $MACRO_TOKEN_ADVANCE(); if ($MACRO_STREAM_ADVANCE_LINE() === false) { goto TOKENIZER_END; } goto TOKENIZER_TOP; TOKENIZER_END: array_pop($tokens); return $tokens; } } php-zend-code-3.4.1/src/Scanner/FileScanner.php000066400000000000000000000024441357431215700212520ustar00rootroot00000000000000file = $file; if (! file_exists($file)) { throw new Exception\InvalidArgumentException(sprintf( 'File "%s" not found', $file )); } parent::__construct(token_get_all(file_get_contents($file)), $annotationManager); } /** * @return string */ public function getFile() { return $this->file; } } php-zend-code-3.4.1/src/Scanner/FunctionScanner.php000066400000000000000000000007371357431215700221630ustar00rootroot00000000000000tokens = $methodTokens; $this->nameInformation = $nameInformation; } /** * @param string $class * @return MethodScanner */ public function setClass($class) { $this->class = (string) $class; return $this; } /** * @param ClassScanner $scannerClass * @return MethodScanner */ public function setScannerClass(ClassScanner $scannerClass) { $this->scannerClass = $scannerClass; return $this; } /** * @return ClassScanner */ public function getClassScanner() { return $this->scannerClass; } /** * @return string */ public function getName() { $this->scan(); return $this->name; } /** * @return int */ public function getLineStart() { $this->scan(); return $this->lineStart; } /** * @return int */ public function getLineEnd() { $this->scan(); return $this->lineEnd; } /** * @return string */ public function getDocComment() { $this->scan(); return $this->docComment; } /** * @param AnnotationManager $annotationManager * @return AnnotationScanner|false */ public function getAnnotations(AnnotationManager $annotationManager) { if (($docComment = $this->getDocComment()) == '') { return false; } return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation); } /** * @return bool */ public function isFinal() { $this->scan(); return $this->isFinal; } /** * @return bool */ public function isAbstract() { $this->scan(); return $this->isAbstract; } /** * @return bool */ public function isPublic() { $this->scan(); return $this->isPublic; } /** * @return bool */ public function isProtected() { $this->scan(); return $this->isProtected; } /** * @return bool */ public function isPrivate() { $this->scan(); return $this->isPrivate; } /** * @return bool */ public function isStatic() { $this->scan(); return $this->isStatic; } /** * Override the given name for a method, this is necessary to * support traits. * * @param string $name * @return self */ public function setName($name) { $this->name = $name; return $this; } /** * Visibility must be of T_PUBLIC, T_PRIVATE or T_PROTECTED * Needed to support traits * * @param int $visibility T_PUBLIC | T_PRIVATE | T_PROTECTED * @return self * @throws \Zend\Code\Exception\InvalidArgumentException */ public function setVisibility($visibility) { switch ($visibility) { case T_PUBLIC: $this->isPublic = true; $this->isPrivate = false; $this->isProtected = false; break; case T_PRIVATE: $this->isPublic = false; $this->isPrivate = true; $this->isProtected = false; break; case T_PROTECTED: $this->isPublic = false; $this->isPrivate = false; $this->isProtected = true; break; default: throw new Exception\InvalidArgumentException('Invalid visibility argument passed to setVisibility.'); } return $this; } /** * @return int */ public function getNumberOfParameters() { return count($this->getParameters()); } /** * @param bool $returnScanner * @return array */ public function getParameters($returnScanner = false) { $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] != 'parameter') { continue; } if (! $returnScanner) { $return[] = $info['name']; } else { $return[] = $this->getParameter($info['name']); } } return $return; } /** * @param int|string $parameterNameOrInfoIndex * @return ParameterScanner * @throws Exception\InvalidArgumentException */ public function getParameter($parameterNameOrInfoIndex) { $this->scan(); if (is_int($parameterNameOrInfoIndex)) { $info = $this->infos[$parameterNameOrInfoIndex]; if ($info['type'] != 'parameter') { throw new Exception\InvalidArgumentException('Index of info offset is not about a parameter'); } } elseif (is_string($parameterNameOrInfoIndex)) { foreach ($this->infos as $info) { if ($info['type'] === 'parameter' && $info['name'] === $parameterNameOrInfoIndex) { break; } unset($info); } if (! isset($info)) { throw new Exception\InvalidArgumentException('Index of info offset is not about a parameter'); } } $p = new ParameterScanner( array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart']), $this->nameInformation ); $p->setDeclaringFunction($this->name); $p->setDeclaringScannerFunction($this); $p->setDeclaringClass($this->class); $p->setDeclaringScannerClass($this->scannerClass); $p->setPosition($info['position']); return $p; } /** * @return string */ public function getBody() { $this->scan(); return $this->body; } public static function export() { // @todo } public function __toString() { $this->scan(); return var_export($this, true); } protected function scan() { if ($this->isScanned) { return; } if (! $this->tokens) { throw new Exception\RuntimeException('No tokens were provided'); } /** * Variables & Setup */ $tokens = &$this->tokens; // localize $infos = &$this->infos; // localize $tokenIndex = null; $token = null; $tokenType = null; $tokenContent = null; $tokenLine = null; $infoIndex = 0; $parentCount = 0; /* * MACRO creation */ $MACRO_TOKEN_ADVANCE = function () use ( &$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine ) { static $lastTokenArray = null; $tokenIndex = $tokenIndex === null ? 0 : $tokenIndex + 1; if (! isset($tokens[$tokenIndex])) { $token = false; $tokenContent = false; $tokenType = false; $tokenLine = false; return false; } $token = $tokens[$tokenIndex]; if (is_string($token)) { $tokenType = null; $tokenContent = $token; $tokenLine += substr_count( $lastTokenArray[1] ?? '', "\n" ); // adjust token line by last known newline count } else { $lastTokenArray = $token; [$tokenType, $tokenContent, $tokenLine] = $token; } return $tokenIndex; }; $MACRO_INFO_START = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) { $infos[$infoIndex] = [ 'type' => 'parameter', 'tokenStart' => $tokenIndex, 'tokenEnd' => null, 'lineStart' => $tokenLine, 'lineEnd' => $tokenLine, 'name' => null, 'position' => $infoIndex + 1, // position is +1 of infoIndex ]; }; $MACRO_INFO_ADVANCE = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) { $infos[$infoIndex]['tokenEnd'] = $tokenIndex; $infos[$infoIndex]['lineEnd'] = $tokenLine; $infoIndex++; return $infoIndex; }; /** * START FINITE STATE MACHINE FOR SCANNING TOKENS */ // Initialize token $MACRO_TOKEN_ADVANCE(); SCANNER_TOP: $this->lineStart = $this->lineStart ? : $tokenLine; switch ($tokenType) { case T_DOC_COMMENT: $this->lineStart = null; if ($this->docComment === null && $this->name === null) { $this->docComment = $tokenContent; } goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case T_FINAL: $this->isFinal = true; goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case T_ABSTRACT: $this->isAbstract = true; goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case T_PUBLIC: // use defaults goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case T_PROTECTED: $this->setVisibility(T_PROTECTED); goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case T_PRIVATE: $this->setVisibility(T_PRIVATE); goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case T_STATIC: $this->isStatic = true; goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case T_NS_SEPARATOR: if (! isset($infos[$infoIndex])) { $MACRO_INFO_START(); } goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case T_VARIABLE: case T_STRING: if ($tokenType === T_STRING && $parentCount === 0) { $this->name = $tokenContent; } if ($parentCount === 1) { if (! isset($infos[$infoIndex])) { $MACRO_INFO_START(); } if ($tokenType === T_VARIABLE) { $infos[$infoIndex]['name'] = ltrim($tokenContent, '$'); } } goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case null: switch ($tokenContent) { case '&': if (! isset($infos[$infoIndex])) { $MACRO_INFO_START(); } goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case '(': $parentCount++; goto SCANNER_CONTINUE_SIGNATURE; // goto (no break needed); case ')': $parentCount--; if ($parentCount > 0) { goto SCANNER_CONTINUE_SIGNATURE; } if ($parentCount === 0) { if ($infos) { $MACRO_INFO_ADVANCE(); } $context = 'body'; } goto SCANNER_CONTINUE_BODY; // goto (no break needed); case ',': if ($parentCount === 1) { $MACRO_INFO_ADVANCE(); } goto SCANNER_CONTINUE_SIGNATURE; } } SCANNER_CONTINUE_SIGNATURE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_TOP; SCANNER_CONTINUE_BODY: $braceCount = 0; while ($MACRO_TOKEN_ADVANCE() !== false) { if ($tokenContent == '}') { $braceCount--; } if ($braceCount > 0) { $this->body .= $tokenContent; } if ($tokenContent == '{') { $braceCount++; } $this->lineEnd = $tokenLine; } SCANNER_END: $this->isScanned = true; } } php-zend-code-3.4.1/src/Scanner/ParameterScanner.php000066400000000000000000000151241357431215700223120ustar00rootroot00000000000000tokens = $parameterTokens; $this->nameInformation = $nameInformation; } /** * Set declaring class * * @param string $class * @return void */ public function setDeclaringClass($class) { $this->declaringClass = (string) $class; } /** * Set declaring scanner class * * @param ClassScanner $scannerClass * @return void */ public function setDeclaringScannerClass(ClassScanner $scannerClass) { $this->declaringScannerClass = $scannerClass; } /** * Set declaring function * * @param string $function * @return void */ public function setDeclaringFunction($function) { $this->declaringFunction = $function; } /** * Set declaring scanner function * * @param MethodScanner $scannerFunction * @return void */ public function setDeclaringScannerFunction(MethodScanner $scannerFunction) { $this->declaringScannerFunction = $scannerFunction; } /** * Set position * * @param int $position * @return void */ public function setPosition($position) { $this->position = $position; } /** * Scan * * @return void */ protected function scan() { if ($this->isScanned) { return; } $tokens = &$this->tokens; reset($tokens); SCANNER_TOP: $token = current($tokens); if (is_string($token)) { // check pass by ref if ($token === '&') { $this->isPassedByReference = true; goto SCANNER_CONTINUE; } if ($token === '=') { $this->isOptional = true; $this->isDefaultValueAvailable = true; goto SCANNER_CONTINUE; } } else { if ($this->name === null && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR)) { $this->class .= $token[1]; goto SCANNER_CONTINUE; } if ($token[0] === T_VARIABLE) { $this->name = ltrim($token[1], '$'); goto SCANNER_CONTINUE; } } if ($this->name !== null) { $this->defaultValue .= trim(is_string($token) ? $token : $token[1]); } SCANNER_CONTINUE: if (next($this->tokens) === false) { goto SCANNER_END; } goto SCANNER_TOP; SCANNER_END: if ($this->class && $this->nameInformation) { $this->class = $this->nameInformation->resolveName($this->class); } $this->isScanned = true; } /** * Get declaring scanner class * * @return ClassScanner */ public function getDeclaringScannerClass() { return $this->declaringScannerClass; } /** * Get declaring class * * @return string */ public function getDeclaringClass() { return $this->declaringClass; } /** * Get declaring scanner function * * @return MethodScanner */ public function getDeclaringScannerFunction() { return $this->declaringScannerFunction; } /** * Get declaring function * * @return string */ public function getDeclaringFunction() { return $this->declaringFunction; } /** * Get default value * * @return string */ public function getDefaultValue() { $this->scan(); return $this->defaultValue; } /** * Get class * * @return string */ public function getClass() { $this->scan(); return $this->class; } /** * Get name * * @return string */ public function getName() { $this->scan(); return $this->name; } /** * Get position * * @return int */ public function getPosition() { $this->scan(); return $this->position; } /** * Check if is array * * @return bool */ public function isArray() { $this->scan(); return $this->isArray; } /** * Check if default value is available * * @return bool */ public function isDefaultValueAvailable() { $this->scan(); return $this->isDefaultValueAvailable; } /** * Check if is optional * * @return bool */ public function isOptional() { $this->scan(); return $this->isOptional; } /** * Check if is passed by reference * * @return bool */ public function isPassedByReference() { $this->scan(); return $this->isPassedByReference; } } php-zend-code-3.4.1/src/Scanner/PropertyScanner.php000066400000000000000000000155531357431215700222240ustar00rootroot00000000000000tokens = $propertyTokens; $this->nameInformation = $nameInformation; } /** * @param string $class */ public function setClass($class) { $this->class = $class; } /** * @param ClassScanner $scannerClass */ public function setScannerClass(ClassScanner $scannerClass) { $this->scannerClass = $scannerClass; } /** * @return ClassScanner */ public function getClassScanner() { return $this->scannerClass; } /** * @return string */ public function getName() { $this->scan(); return $this->name; } /** * @return string */ public function getValueType() { $this->scan(); return $this->valueType; } /** * @return bool */ public function isPublic() { $this->scan(); return $this->isPublic; } /** * @return bool */ public function isPrivate() { $this->scan(); return $this->isPrivate; } /** * @return bool */ public function isProtected() { $this->scan(); return $this->isProtected; } /** * @return bool */ public function isStatic() { $this->scan(); return $this->isStatic; } /** * @return string */ public function getValue() { $this->scan(); return $this->value; } /** * @return string */ public function getDocComment() { $this->scan(); return $this->docComment; } /** * @param Annotation\AnnotationManager $annotationManager * @return AnnotationScanner|false */ public function getAnnotations(Annotation\AnnotationManager $annotationManager) { if (($docComment = $this->getDocComment()) == '') { return false; } return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation); } /** * @return string */ public function __toString() { $this->scan(); return var_export($this, true); } /** * Scan tokens * * @throws \Zend\Code\Exception\RuntimeException */ protected function scan() { if ($this->isScanned) { return; } if (! $this->tokens) { throw new Exception\RuntimeException('No tokens were provided'); } /** * Variables & Setup */ $value = ''; $concatenateValue = false; $tokens = &$this->tokens; reset($tokens); foreach ($tokens as $token) { $tempValue = $token; if (! is_string($token)) { list($tokenType, $tokenContent, $tokenLine) = $token; switch ($tokenType) { case T_DOC_COMMENT: if ($this->docComment === null && $this->name === null) { $this->docComment = $tokenContent; } break; case T_VARIABLE: $this->name = ltrim($tokenContent, '$'); break; case T_PUBLIC: // use defaults break; case T_PROTECTED: $this->isProtected = true; $this->isPublic = false; break; case T_PRIVATE: $this->isPrivate = true; $this->isPublic = false; break; case T_STATIC: $this->isStatic = true; break; default: $tempValue = trim($tokenContent); break; } } //end value concatenation if (! is_array($token) && trim($token) == ';') { $concatenateValue = false; } if (true === $concatenateValue) { $value .= $tempValue; } //start value concatenation if (! is_array($token) && trim($token) == '=') { $concatenateValue = true; } } $this->valueType = self::T_UNKNOWN; if ($value == 'false' || $value == 'true') { $this->valueType = self::T_BOOLEAN; } elseif (is_numeric($value)) { $this->valueType = self::T_INTEGER; } elseif (0 === strpos($value, 'array') || 0 === strpos($value, '[')) { $this->valueType = self::T_ARRAY; } elseif (0 === strpos($value, '"') || 0 === strpos($value, "'")) { $value = substr($value, 1, -1); // Remove quotes $this->valueType = self::T_STRING; } $this->value = empty($value) ? null : $value; $this->isScanned = true; } } php-zend-code-3.4.1/src/Scanner/ScannerInterface.php000066400000000000000000000007131357431215700222700ustar00rootroot00000000000000tokens = $tokens; $this->annotationManager = $annotationManager; } /** * @return AnnotationManager */ public function getAnnotationManager() { return $this->annotationManager; } /** * Get doc comment * * @todo Assignment of $this->docComment should probably be done in scan() * and then $this->getDocComment() just retrieves it. * * @return string|null */ public function getDocComment() { foreach ($this->tokens as $token) { $type = $token[0]; $value = $token[1]; if (($type == T_OPEN_TAG) || ($type == T_WHITESPACE)) { continue; } elseif ($type == T_DOC_COMMENT) { $this->docComment = $value; return $this->docComment; } else { // Only whitespace is allowed before file docblocks return; } } } /** * @return array */ public function getNamespaces() { $this->scan(); $namespaces = []; foreach ($this->infos as $info) { if ($info['type'] == 'namespace') { $namespaces[] = $info['namespace']; } } return $namespaces; } /** * @param null|string $namespace * @return array|null */ public function getUses($namespace = null) { $this->scan(); return $this->getUsesNoScan($namespace); } /** * @return void */ public function getIncludes() { $this->scan(); // @todo Implement getIncludes() in TokenArrayScanner } /** * @return array */ public function getClassNames() { $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] != 'class') { continue; } $return[] = $info['name']; } return $return; } /** * @return ClassScanner[] */ public function getClasses() { $this->scan(); $return = []; foreach ($this->infos as $info) { if ($info['type'] != 'class') { continue; } $return[] = $this->getClass($info['name']); } return $return; } /** * Return the class object from this scanner * * @param string|int $name * @throws Exception\InvalidArgumentException * @return ClassScanner|false */ public function getClass($name) { $this->scan(); if (is_int($name)) { $info = $this->infos[$name]; if ($info['type'] != 'class') { throw new Exception\InvalidArgumentException('Index of info offset is not about a class'); } } elseif (is_string($name)) { $classFound = false; foreach ($this->infos as $info) { if ($info['type'] === 'class' && $info['name'] === $name) { $classFound = true; break; } } if (! $classFound) { return false; } } return new ClassScanner( array_slice( $this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart'] + 1 ), // zero indexed array new NameInformation($info['namespace'], $info['uses']) ); } /** * @param string $className * @return bool|null|NameInformation */ public function getClassNameInformation($className) { $this->scan(); $classFound = false; foreach ($this->infos as $info) { if ($info['type'] === 'class' && $info['name'] === $className) { $classFound = true; break; } } if (! $classFound) { return false; } if (! isset($info)) { return; } return new NameInformation($info['namespace'], $info['uses']); } /** * @return array */ public function getFunctionNames() { $this->scan(); $functionNames = []; foreach ($this->infos as $info) { if ($info['type'] == 'function') { $functionNames[] = $info['name']; } } return $functionNames; } /** * @return array */ public function getFunctions() { $this->scan(); $functions = []; // foreach ($this->infos as $info) { // if ($info['type'] == 'function') { // // @todo $functions[] = new FunctionScanner($info['name']); // } // } return $functions; } /** * Export * * @param mixed $tokens */ public static function export($tokens) { // @todo } public function __toString() { // @todo } /** * Scan * * @todo: $this->docComment should be assigned for valid docblock during * the scan instead of $this->getDocComment() (starting with * T_DOC_COMMENT case) * * @throws Exception\RuntimeException */ protected function scan() { if ($this->isScanned) { return; } if (! $this->tokens) { throw new Exception\RuntimeException('No tokens were provided'); } /** * Variables & Setup */ $tokens = &$this->tokens; // localize $infos = &$this->infos; // localize $tokenIndex = null; $token = null; $tokenType = null; $tokenContent = null; $tokenLine = null; $namespace = null; $docCommentIndex = false; $infoIndex = 0; /* * MACRO creation */ $MACRO_TOKEN_ADVANCE = function () use ( &$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine ) { $tokenIndex = $tokenIndex === null ? 0 : $tokenIndex + 1; if (! isset($tokens[$tokenIndex])) { $token = false; $tokenContent = false; $tokenType = false; $tokenLine = false; return false; } if (is_string($tokens[$tokenIndex]) && $tokens[$tokenIndex] === '"') { do { $tokenIndex++; } while (! (is_string($tokens[$tokenIndex]) && $tokens[$tokenIndex] === '"')); } $token = $tokens[$tokenIndex]; if (is_array($token)) { list($tokenType, $tokenContent, $tokenLine) = $token; } else { $tokenType = null; $tokenContent = $token; } return $tokenIndex; }; $MACRO_TOKEN_LOGICAL_START_INDEX = function () use (&$tokenIndex, &$docCommentIndex) { return $docCommentIndex === false ? $tokenIndex : $docCommentIndex; }; $MACRO_DOC_COMMENT_START = function () use (&$tokenIndex, &$docCommentIndex) { $docCommentIndex = $tokenIndex; return $docCommentIndex; }; $MACRO_DOC_COMMENT_VALIDATE = function () use (&$tokenType, &$docCommentIndex) { static $validTrailingTokens = null; if ($validTrailingTokens === null) { $validTrailingTokens = [T_WHITESPACE, T_FINAL, T_ABSTRACT, T_INTERFACE, T_CLASS, T_FUNCTION]; } if ($docCommentIndex !== false && ! in_array($tokenType, $validTrailingTokens)) { $docCommentIndex = false; } return $docCommentIndex; }; $MACRO_INFO_ADVANCE = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) { $infos[$infoIndex]['tokenEnd'] = $tokenIndex; $infos[$infoIndex]['lineEnd'] = $tokenLine; $infoIndex++; return $infoIndex; }; /** * START FINITE STATE MACHINE FOR SCANNING TOKENS */ // Initialize token $MACRO_TOKEN_ADVANCE(); SCANNER_TOP: if ($token === false) { goto SCANNER_END; } // Validate current doc comment index $MACRO_DOC_COMMENT_VALIDATE(); switch ($tokenType) { case T_DOC_COMMENT: $MACRO_DOC_COMMENT_START(); goto SCANNER_CONTINUE; // goto no break needed case T_NAMESPACE: $infos[$infoIndex] = [ 'type' => 'namespace', 'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(), 'tokenEnd' => null, 'lineStart' => $token[2], 'lineEnd' => null, 'namespace' => null, ]; // start processing with next token if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } SCANNER_NAMESPACE_TOP: if (($tokenType === null && $tokenContent === ';') || $tokenContent === '{') { goto SCANNER_NAMESPACE_END; } if ($tokenType === T_WHITESPACE) { goto SCANNER_NAMESPACE_CONTINUE; } if ($tokenType === T_NS_SEPARATOR || $tokenType === T_STRING) { $infos[$infoIndex]['namespace'] .= $tokenContent; } SCANNER_NAMESPACE_CONTINUE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_NAMESPACE_TOP; SCANNER_NAMESPACE_END: $namespace = $infos[$infoIndex]['namespace']; $MACRO_INFO_ADVANCE(); goto SCANNER_CONTINUE; // goto no break needed case T_USE: $infos[$infoIndex] = [ 'type' => 'use', 'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(), 'tokenEnd' => null, 'lineStart' => $tokens[$tokenIndex][2], 'lineEnd' => null, 'namespace' => $namespace, 'statements' => [ 0 => [ 'use' => null, 'as' => null, ], ], ]; $useStatementIndex = 0; $useAsContext = false; // start processing with next token if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } SCANNER_USE_TOP: if ($tokenType === null) { if ($tokenContent === ';') { goto SCANNER_USE_END; } elseif ($tokenContent === ',') { $useAsContext = false; $useStatementIndex++; $infos[$infoIndex]['statements'][$useStatementIndex] = [ 'use' => null, 'as' => null, ]; } } // ANALYZE if ($tokenType !== null) { if ($tokenType == T_AS) { $useAsContext = true; goto SCANNER_USE_CONTINUE; } if ($tokenType == T_NS_SEPARATOR || $tokenType == T_STRING) { if ($useAsContext == false) { $infos[$infoIndex]['statements'][$useStatementIndex]['use'] .= $tokenContent; } else { $infos[$infoIndex]['statements'][$useStatementIndex]['as'] = $tokenContent; } } } SCANNER_USE_CONTINUE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_USE_TOP; SCANNER_USE_END: $MACRO_INFO_ADVANCE(); goto SCANNER_CONTINUE; // goto no break needed case T_INCLUDE: case T_INCLUDE_ONCE: case T_REQUIRE: case T_REQUIRE_ONCE: // Static for performance static $includeTypes = [ T_INCLUDE => 'include', T_INCLUDE_ONCE => 'include_once', T_REQUIRE => 'require', T_REQUIRE_ONCE => 'require_once', ]; $infos[$infoIndex] = [ 'type' => 'include', 'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(), 'tokenEnd' => null, 'lineStart' => $tokens[$tokenIndex][2], 'lineEnd' => null, 'includeType' => $includeTypes[$tokens[$tokenIndex][0]], 'path' => '', ]; // start processing with next token if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } SCANNER_INCLUDE_TOP: if ($tokenType === null && $tokenContent === ';') { goto SCANNER_INCLUDE_END; } $infos[$infoIndex]['path'] .= $tokenContent; SCANNER_INCLUDE_CONTINUE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_INCLUDE_TOP; SCANNER_INCLUDE_END: $MACRO_INFO_ADVANCE(); goto SCANNER_CONTINUE; // goto no break needed case T_FUNCTION: case T_FINAL: case T_ABSTRACT: case T_CLASS: case T_INTERFACE: case T_TRAIT: $infos[$infoIndex] = [ 'type' => $tokenType === T_FUNCTION ? 'function' : 'class', 'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(), 'tokenEnd' => null, 'lineStart' => $tokens[$tokenIndex][2], 'lineEnd' => null, 'namespace' => $namespace, 'uses' => $this->getUsesNoScan($namespace), 'name' => null, 'shortName' => null, ]; $classBraceCount = 0; // start processing with current token SCANNER_CLASS_TOP: // process the name if ($infos[$infoIndex]['shortName'] == '' && (($tokenType === T_CLASS || $tokenType === T_INTERFACE || $tokenType === T_TRAIT) && $infos[$infoIndex]['type'] === 'class' || ($tokenType === T_FUNCTION && $infos[$infoIndex]['type'] === 'function')) ) { $infos[$infoIndex]['shortName'] = is_array($tokens[$tokenIndex + 2]) ? $tokens[$tokenIndex + 2][1] : $tokens[$tokenIndex + 2]; $infos[$infoIndex]['name'] = ($namespace !== null ? $namespace . '\\' : '') . $infos[$infoIndex]['shortName']; } if ($tokenType === null) { if ($tokenContent == '{') { $classBraceCount++; } if ($tokenContent == '}') { $classBraceCount--; if ($classBraceCount === 0) { goto SCANNER_CLASS_END; } } } SCANNER_CLASS_CONTINUE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_CLASS_TOP; SCANNER_CLASS_END: $MACRO_INFO_ADVANCE(); goto SCANNER_CONTINUE; // goto no break needed } SCANNER_CONTINUE: if ($MACRO_TOKEN_ADVANCE() === false) { goto SCANNER_END; } goto SCANNER_TOP; SCANNER_END: /** * END FINITE STATE MACHINE FOR SCANNING TOKENS */ $this->isScanned = true; } /** * Check for namespace * * @param string $namespace * @return bool */ public function hasNamespace($namespace) { $this->scan(); foreach ($this->infos as $info) { if ($info['type'] == 'namespace' && $info['namespace'] == $namespace) { return true; } } return false; } /** * @param string $namespace * @return null|array * @throws Exception\InvalidArgumentException */ protected function getUsesNoScan($namespace) { $namespaces = []; foreach ($this->infos as $info) { if ($info['type'] == 'namespace') { $namespaces[] = $info['namespace']; } } if ($namespace === null) { $namespace = array_shift($namespaces); } elseif (! is_string($namespace)) { throw new Exception\InvalidArgumentException('Invalid namespace provided'); } elseif (! in_array($namespace, $namespaces)) { return; } $uses = []; foreach ($this->infos as $info) { if ($info['type'] !== 'use') { continue; } foreach ($info['statements'] as $statement) { if ($info['namespace'] == $namespace) { $uses[] = $statement; } } } return $uses; } } php-zend-code-3.4.1/src/Scanner/Util.php000066400000000000000000000044141357431215700177750ustar00rootroot00000000000000namespace && ! $data->uses && strlen($value) > 0 && $value[0] != '\\') { $value = $data->namespace . '\\' . $value; return; } if (! $data->uses || strlen($value) <= 0 || $value[0] == '\\') { $value = ltrim($value, '\\'); return; } if ($data->namespace || $data->uses) { $firstPart = $value; if (($firstPartEnd = strpos($firstPart, '\\')) !== false) { $firstPart = substr($firstPart, 0, $firstPartEnd); } else { $firstPartEnd = strlen($firstPart); } if (array_key_exists($firstPart, $data->uses)) { $value = substr_replace($value, $data->uses[$firstPart], 0, $firstPartEnd); return; } if ($data->namespace) { $value = $data->namespace . '\\' . $value; return; } } } } php-zend-code-3.4.1/src/Scanner/ValueScanner.php000066400000000000000000000005701357431215700214450ustar00rootroot00000000000000markTestSkipped( 'Enable TESTS_ZEND_CODE_ANNOTATION_DOCTRINE_SUPPORT to test doctrine annotation parsing' ); } $this->manager = new Annotation\AnnotationManager(); } public function testAllowsMultipleParsingStrategies() { $genericParser = new Annotation\Parser\GenericAnnotationParser(); $genericParser->registerAnnotation(TestAsset\Foo::class); $doctrineParser = new Annotation\Parser\DoctrineAnnotationParser(); $doctrineParser->registerAnnotation(TestAsset\DoctrineAnnotation::class); $this->manager->attach($genericParser); $this->manager->attach($doctrineParser); $reflection = new Reflection\ClassReflection(TestAsset\EntityWithMixedAnnotations::class); $prop = $reflection->getProperty('test'); $annotations = $prop->getAnnotations($this->manager); self::assertTrue($annotations->hasAnnotation(TestAsset\Foo::class)); self::assertTrue($annotations->hasAnnotation(TestAsset\DoctrineAnnotation::class)); self::assertFalse($annotations->hasAnnotation(TestAsset\Bar::class)); foreach ($annotations as $annotation) { switch (get_class($annotation)) { case TestAsset\Foo::class: self::assertEquals('first', $annotation->content); break; case TestAsset\DoctrineAnnotation::class: self::assertEquals(['foo' => 'bar', 'bar' => 'baz'], $annotation->value); break; default: $this->fail('Received unexpected annotation "' . get_class($annotation) . '"'); } } } } php-zend-code-3.4.1/test/Annotation/DoctrineAnnotationParserTest.php000066400000000000000000000063531357431215700256140ustar00rootroot00000000000000markTestSkipped( 'Enable TESTS_ZEND_CODE_ANNOTATION_DOCTRINE_SUPPORT to test doctrine annotation parsing' ); } $this->parser = new DoctrineAnnotationParser(); } public function getEvent() { $event = new Event(); $event->setParams([ 'class' => __NAMESPACE__ . '\TestAsset\DoctrineAnnotation', 'content' => '(foo="bar")', 'raw' => '@' . __NAMESPACE__ . '\TestAsset\DoctrineAnnotation(foo="bar")', ]); return $event; } public function testParserCreatesNewAnnotationInstances() { $this->parser->registerAnnotation(__NAMESPACE__ . '\TestAsset\DoctrineAnnotation'); $event = $this->getEvent(); $test = $this->parser->onCreateAnnotation($event); self::assertInstanceOf(__NAMESPACE__ . '\TestAsset\DoctrineAnnotation', $test); self::assertEquals(['foo' => 'bar'], $test->value); } public function testReturnsFalseDuringCreationIfAnnotationIsNotRegistered() { $event = $this->getEvent(); self::assertFalse($this->parser->onCreateAnnotation($event)); } public function testReturnsFalseClassNotSet() { self::assertFalse($this->parser->onCreateAnnotation(new Event())); } public function testReturnsFalseRawNotSet() { $this->parser->registerAnnotation(__NAMESPACE__ . '\TestAsset\DoctrineAnnotation'); $event = $this->getEvent(); $event->setParam('raw', false); self::assertFalse($this->parser->onCreateAnnotation($event)); } public function testReturnsFalseEmptyAnnotations() { $this->parser->registerAnnotation(__NAMESPACE__ . '\TestAsset\DoctrineAnnotation'); $event = $this->getEvent(); $event->setParam('raw', 'foo'); self::assertFalse($this->parser->onCreateAnnotation($event)); } public function testRegisterAnnotationsThrowsException() { $this->expectException(InvalidArgumentException::class); $this->parser->registerAnnotations('some string'); } public function testRegisterAnnotations() { $this->parser->registerAnnotations([__NAMESPACE__ . '\TestAsset\DoctrineAnnotation']); $event = $this->getEvent(); $test = $this->parser->onCreateAnnotation($event); self::assertInstanceOf(__NAMESPACE__ . '\TestAsset\DoctrineAnnotation', $test); self::assertEquals(['foo' => 'bar'], $test->value); } } php-zend-code-3.4.1/test/Annotation/GenericAnnotationParserTest.php000066400000000000000000000102561357431215700254160ustar00rootroot00000000000000parser = new Annotation\Parser\GenericAnnotationParser(); } public function getFooEvent() { $event = new Event(); $event->setParams([ 'class' => __NAMESPACE__ . '\TestAsset\Foo', 'content' => '(test content)', 'raw' => '@' . __NAMESPACE__ . '\TestAsset\Foo(test content)', ]); return $event; } public function testParserKeepsTrackOfAllowedAnnotations() { $this->parser->registerAnnotation(new TestAsset\Foo()); $this->parser->registerAnnotation(new TestAsset\Bar()); self::assertTrue($this->parser->hasAnnotation(__NAMESPACE__ . '\TestAsset\Foo')); self::assertTrue($this->parser->hasAnnotation(__NAMESPACE__ . '\TestAsset\Bar')); self::assertFalse($this->parser->hasAnnotation(__NAMESPACE__ . '\TestAsset\Bogus')); } public function testParserCreatesNewAnnotationInstances() { $foo = new TestAsset\Foo(); $this->parser->registerAnnotation($foo); $event = $this->getFooEvent(); $test = $this->parser->onCreateAnnotation($event); self::assertInstanceOf(__NAMESPACE__ . '\TestAsset\Foo', $test); self::assertNotSame($foo, $test); self::assertEquals('test content', $test->content); } public function testReturnsFalseDuringCreationIfAnnotationIsNotRegistered() { $event = $this->getFooEvent(); self::assertFalse($this->parser->onCreateAnnotation($event)); } public function testParserAllowsPassingArrayOfAnnotationInstances() { $this->parser->registerAnnotations([ new TestAsset\Foo(), new TestAsset\Bar(), ]); self::assertTrue($this->parser->hasAnnotation(__NAMESPACE__ . '\TestAsset\Foo')); self::assertTrue($this->parser->hasAnnotation(__NAMESPACE__ . '\TestAsset\Bar')); } public function testAllowsSpecifyingAliases() { $bar = new TestAsset\Bar(); $this->parser->registerAnnotation($bar); $this->parser->setAlias(__NAMESPACE__ . '\TestAsset\Foo', get_class($bar)); $event = $this->getFooEvent(); $test = $this->parser->onCreateAnnotation($event); self::assertInstanceOf(__NAMESPACE__ . '\TestAsset\Bar', $test); self::assertNotSame($bar, $test); self::assertEquals('test content', $test->content); } public function testRegisterAnnotationAllowsAnnotationInterfaceOnly() { $this->expectException(InvalidArgumentException::class); $this->parser->registerAnnotation(new \stdClass()); } public function testAllowRegistrationOnceOnly() { $bar = new TestAsset\Bar(); $this->parser->registerAnnotation($bar); $this->expectException(InvalidArgumentException::class); $this->parser->registerAnnotation($bar); } public function testRegisterAnnotations() { $this->parser->registerAnnotations([new TestAsset\Foo()]); $event = $this->getFooEvent(); $test = $this->parser->onCreateAnnotation($event); self::assertInstanceOf(__NAMESPACE__ . '\TestAsset\Foo', $test); } public function testRegisterAnnotationsThrowsException() { $this->expectException(InvalidArgumentException::class); $this->parser->registerAnnotations('some string'); } public function testSetAliasNotRegisteredClassThrowsException() { $this->expectException(InvalidArgumentException::class); $this->parser->setAlias('bar', 'foo'); } } php-zend-code-3.4.1/test/Annotation/TestAsset/000077500000000000000000000000001357431215700211745ustar00rootroot00000000000000php-zend-code-3.4.1/test/Annotation/TestAsset/Bar.php000066400000000000000000000010571357431215700224140ustar00rootroot00000000000000content = $content; } } php-zend-code-3.4.1/test/Annotation/TestAsset/DoctrineAnnotation.php000066400000000000000000000010061357431215700255040ustar00rootroot00000000000000value = $value; } } php-zend-code-3.4.1/test/Annotation/TestAsset/EntityWithAnnotations.php000066400000000000000000000011171357431215700262330ustar00rootroot00000000000000content = $content; } } php-zend-code-3.4.1/test/Generator/000077500000000000000000000000001357431215700170715ustar00rootroot00000000000000php-zend-code-3.4.1/test/Generator/AbstractGeneratorTest.php000066400000000000000000000023011357431215700240500ustar00rootroot00000000000000getMockForAbstractClass(AbstractGenerator::class, [ [ 'indentation' => 'foo', ], ]); self::assertInstanceOf(GeneratorInterface::class, $generator); self::assertEquals('foo', $generator->getIndentation()); } public function testSetOptionsThrowsExceptionOnInvalidArgument() { $this->expectException(InvalidArgumentException::class); $this->getMockForAbstractClass(AbstractGenerator::class, ['sss']); } } php-zend-code-3.4.1/test/Generator/AbstractMemberGeneratorTest.php000066400000000000000000000034631357431215700252120ustar00rootroot00000000000000fixture = $this->getMockForAbstractClass(AbstractMemberGenerator::class); } public function testSetFlagsWithArray() { $this->fixture->setFlags( [ AbstractMemberGenerator::FLAG_FINAL, AbstractMemberGenerator::FLAG_PUBLIC, ] ); self::assertEquals(AbstractMemberGenerator::VISIBILITY_PUBLIC, $this->fixture->getVisibility()); self::assertEquals(true, $this->fixture->isFinal()); } public function testSetDocBlockThrowsExceptionWithInvalidType() { $this->expectException(InvalidArgumentException::class); $this->fixture->setDocBlock(new \stdClass()); } public function testRemoveDocBlock(): void { $this->fixture->setDocBlock(new DocBlockGenerator()); $this->fixture->removeDocBlock(); $this->assertNull($this->fixture->getDocBlock()); } public function testRemoveDocBlockIsIdempotent(): void { $this->fixture->removeDocBlock(); $this->fixture->removeDocBlock(); $this->assertNull($this->fixture->getDocBlock()); } } php-zend-code-3.4.1/test/Generator/ClassGeneratorTest.php000066400000000000000000001233271357431215700233660ustar00rootroot00000000000000setName('TestClass'); self::assertEquals('TestClass', $classGenerator->getName()); } public function testClassDocBlockAccessors() { $docBlockGenerator = new DocBlockGenerator(); $classGenerator = new ClassGenerator(); $classGenerator->setDocBlock($docBlockGenerator); self::assertSame($docBlockGenerator, $classGenerator->getDocBlock()); } public function testAbstractAccessors() { $classGenerator = new ClassGenerator(); self::assertFalse($classGenerator->isAbstract()); $classGenerator->setAbstract(true); self::assertTrue($classGenerator->isAbstract()); } public function testExtendedClassAccessors() { $classGenerator = new ClassGenerator(); $classGenerator->setExtendedClass('ExtendedClass'); self::assertEquals('ExtendedClass', $classGenerator->getExtendedClass()); } public function testHasExtendedClass() { $classGenerator = new ClassGenerator(); $classGenerator->setExtendedClass('ExtendedClass'); self::assertTrue($classGenerator->hasExtentedClass()); } public function testRemoveExtendedClass() { $classGenerator = new ClassGenerator(); $classGenerator->setExtendedClass('ExtendedClass'); self::assertTrue($classGenerator->hasExtentedClass()); $classGenerator->removeExtentedClass(); self::assertFalse($classGenerator->hasExtentedClass()); } public function testImplementedInterfacesAccessors() { $classGenerator = new ClassGenerator(); $classGenerator->setImplementedInterfaces(['Class1', 'Class2']); self::assertEquals(['Class1', 'Class2'], $classGenerator->getImplementedInterfaces()); } public function testHasImplementedInterface() { $classGenerator = new ClassGenerator(); $classGenerator->setImplementedInterfaces(['Class1', 'Class2']); self::assertTrue($classGenerator->hasImplementedInterface('Class1')); } public function testRemoveImplementedInterface() { $classGenerator = new ClassGenerator(); $classGenerator->setImplementedInterfaces(['Class1', 'Class2']); self::assertTrue($classGenerator->hasImplementedInterface('Class1')); $classGenerator->removeImplementedInterface('Class1'); self::assertFalse($classGenerator->hasImplementedInterface('Class1')); self::assertTrue($classGenerator->hasImplementedInterface('Class2')); } public function testPropertyAccessors() { $classGenerator = new ClassGenerator(); $classGenerator->addProperties([ 'propOne', new PropertyGenerator('propTwo'), ]); $properties = $classGenerator->getProperties(); self::assertCount(2, $properties); self::assertInstanceOf(PropertyGenerator::class, current($properties)); $property = $classGenerator->getProperty('propTwo'); self::assertInstanceOf(PropertyGenerator::class, $property); self::assertEquals('propTwo', $property->getName()); // add a new property $classGenerator->addProperty('prop3'); self::assertCount(3, $classGenerator->getProperties()); } public function testSetPropertyAlreadyExistsThrowsException() { $classGenerator = new ClassGenerator(); $classGenerator->addProperty('prop3'); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('A property by name prop3 already exists in this class'); $classGenerator->addProperty('prop3'); } public function testSetPropertyNoArrayOrPropertyThrowsException() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Zend\Code\Generator\ClassGenerator::addProperty expects string for name'); $classGenerator->addProperty(true); } public function testMethodAccessors() { $classGenerator = new ClassGenerator(); $classGenerator->addMethods([ 'methodOne', new MethodGenerator('methodTwo'), ]); $methods = $classGenerator->getMethods(); self::assertCount(2, $methods); self::assertInstanceOf(MethodGenerator::class, current($methods)); $method = $classGenerator->getMethod('methodOne'); self::assertInstanceOf(MethodGenerator::class, $method); self::assertEquals('methodOne', $method->getName()); // add a new property $classGenerator->addMethod('methodThree'); self::assertCount(3, $classGenerator->getMethods()); } public function testSetMethodNoMethodOrArrayThrowsException() { $classGenerator = new ClassGenerator(); $this->expectException(ExceptionInterface::class); $this->expectExceptionMessage('Zend\Code\Generator\ClassGenerator::addMethod expects string for name'); $classGenerator->addMethod(true); } public function testSetMethodNameAlreadyExistsThrowsException() { $methodA = new MethodGenerator(); $methodA->setName('foo'); $methodB = new MethodGenerator(); $methodB->setName('foo'); $classGenerator = new ClassGenerator(); $classGenerator->addMethodFromGenerator($methodA); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('A method by name foo already exists in this class.'); $classGenerator->addMethodFromGenerator($methodB); } /** * @group ZF-7361 */ public function testHasMethod() { $classGenerator = new ClassGenerator(); $classGenerator->addMethod('methodOne'); self::assertTrue($classGenerator->hasMethod('methodOne')); } public function testRemoveMethod() { $classGenerator = new ClassGenerator(); $classGenerator->addMethod('methodOne'); self::assertTrue($classGenerator->hasMethod('methodOne')); $classGenerator->removeMethod('methodOne'); self::assertFalse($classGenerator->hasMethod('methodOne')); } /** * @group ZF-7361 */ public function testHasProperty() { $classGenerator = new ClassGenerator(); $classGenerator->addProperty('propertyOne'); self::assertTrue($classGenerator->hasProperty('propertyOne')); } public function testRemoveProperty() { $classGenerator = new ClassGenerator(); $classGenerator->addProperty('propertyOne'); self::assertTrue($classGenerator->hasProperty('propertyOne')); $classGenerator->removeProperty('propertyOne'); self::assertFalse($classGenerator->hasProperty('propertyOne')); } public function testToString() { $classGenerator = ClassGenerator::fromArray([ 'name' => 'SampleClass', 'flags' => ClassGenerator::FLAG_ABSTRACT, 'extendedClass' => 'ExtendedClassName', 'implementedInterfaces' => ['Iterator', 'Traversable'], 'properties' => [ 'foo', ['name' => 'bar'], ], 'methods' => [ ['name' => 'baz'], ], ]); $expectedOutput = <<generate(); self::assertEquals($expectedOutput, $output, $output); } /** * @group ZF-7909 */ public function testClassFromReflectionThatImplementsInterfaces() { $reflClass = new ClassReflection(TestAsset\ClassWithInterface::class); $classGenerator = ClassGenerator::fromReflection($reflClass); $classGenerator->setSourceDirty(true); $code = $classGenerator->generate(); $expectedClassDef = 'class ClassWithInterface' . ' implements OneInterface' . ', TwoInterface'; self::assertStringContainsString($expectedClassDef, $code); } /** * @group ZF-7909 */ public function testClassFromReflectionDiscardParentImplementedInterfaces() { $reflClass = new ClassReflection(TestAsset\NewClassWithInterface::class); $classGenerator = ClassGenerator::fromReflection($reflClass); $classGenerator->setSourceDirty(true); $code = $classGenerator->generate(); $expectedClassDef = 'class NewClassWithInterface' . ' extends ClassWithInterface' . ' implements ThreeInterface'; self::assertStringContainsString($expectedClassDef, $code); } /** * @group 4988 */ public function testNonNamespaceClassReturnsAllMethods() { require_once __DIR__ . '/../TestAsset/NonNamespaceClass.php'; $reflClass = new ClassReflection('ZendTest_Code_NsTest_BarClass'); $classGenerator = ClassGenerator::fromReflection($reflClass); self::assertCount(1, $classGenerator->getMethods()); } /** * @group ZF-9602 */ public function testSetextendedclassShouldIgnoreEmptyClassnameOnGenerate() { $classGeneratorClass = new ClassGenerator(); $classGeneratorClass ->setName('MyClass') ->setExtendedClass(''); $expected = <<generate()); } /** * @group ZF-9602 */ public function testSetextendedclassShouldNotIgnoreNonEmptyClassnameOnGenerate() { $classGeneratorClass = new ClassGenerator(); $classGeneratorClass ->setName('MyClass') ->setExtendedClass('ParentClass'); $expected = <<generate()); } /** * @group namespace */ public function testCodeGenerationShouldTakeIntoAccountNamespacesFromReflection() { $reflClass = new ClassReflection(TestAsset\ClassWithNamespace::class); $classGenerator = ClassGenerator::fromReflection($reflClass); self::assertEquals('ZendTest\Code\Generator\TestAsset', $classGenerator->getNamespaceName()); self::assertEquals('ClassWithNamespace', $classGenerator->getName()); $expected = <<generate(); self::assertEquals($expected, $received, $received); } /** * @group namespace */ public function testSetNameShouldDetermineIfNamespaceSegmentIsPresent() { $classGeneratorClass = new ClassGenerator(); $classGeneratorClass->setName('My\Namespaced\FunClass'); self::assertEquals('My\Namespaced', $classGeneratorClass->getNamespaceName()); } /** * @group namespace */ public function testPassingANamespacedClassnameShouldGenerateANamespaceDeclaration() { $classGeneratorClass = new ClassGenerator(); $classGeneratorClass->setName('My\Namespaced\FunClass'); $received = $classGeneratorClass->generate(); self::assertStringContainsString('namespace My\Namespaced;', $received, $received); } /** * @group namespace */ public function testPassingANamespacedClassnameShouldGenerateAClassnameWithoutItsNamespace() { $classGeneratorClass = new ClassGenerator(); $classGeneratorClass->setName('My\Namespaced\FunClass'); $received = $classGeneratorClass->generate(); self::assertStringContainsString('class FunClass', $received, $received); } public function testHasUse() { $classGenerator = new ClassGenerator(); $classGenerator->addUse('My\First\Use\Class'); $classGenerator->addUse('My\Second\Use\Class', 'MyAlias'); self::assertTrue($classGenerator->hasUse('My\First\Use\Class')); self::assertTrue($classGenerator->hasUse('My\Second\Use\Class')); } public function testRemoveUse() { $classGenerator = new ClassGenerator(); $classGenerator->addUse('My\First\Use\Class'); $classGenerator->addUse('My\Second\Use\Class', 'MyAlias'); self::assertTrue($classGenerator->hasUse('My\First\Use\Class')); self::assertTrue($classGenerator->hasUse('My\Second\Use\Class')); $classGenerator->removeUse('My\First\Use\Class'); $classGenerator->removeUse('My\Second\Use\Class'); self::assertFalse($classGenerator->hasUse('My\First\Use\Class')); self::assertFalse($classGenerator->hasUse('My\Second\Use\Class')); } public function testHasUseAlias() { $classGenerator = new ClassGenerator(); $classGenerator->addUse('My\First\Use\Class'); $classGenerator->addUse('My\Second\Use\Class', 'MyAlias'); self::assertFalse($classGenerator->hasUseAlias('My\First\Use\Class')); self::assertTrue($classGenerator->hasUseAlias('My\Second\Use\Class')); } public function testRemoveUseAlias() { $classGenerator = new ClassGenerator(); $classGenerator->addUse('My\First\Use\Class', 'MyAlias'); self::assertTrue($classGenerator->hasUseAlias('My\First\Use\Class')); $classGenerator->removeUseAlias('My\First\Use\Class'); self::assertFalse($classGenerator->hasUseAlias('My\First\Use\Class')); } /** * @group ZF2-151 */ public function testAddUses() { $classGenerator = new ClassGenerator(); $classGenerator->setName('My\Class'); $classGenerator->addUse('My\First\Use\Class'); $classGenerator->addUse('My\Second\Use\Class', 'MyAlias'); $generated = $classGenerator->generate(); self::assertStringContainsString('use My\First\Use\Class;', $generated); self::assertStringContainsString('use My\Second\Use\Class as MyAlias;', $generated); } /** * @group 4990 */ public function testAddOneUseTwiceOnlyAddsOne() { $classGenerator = new ClassGenerator(); $classGenerator->setName('My\Class'); $classGenerator->addUse('My\First\Use\Class'); $classGenerator->addUse('My\First\Use\Class'); $generated = $classGenerator->generate(); self::assertCount(1, $classGenerator->getUses()); self::assertStringContainsString('use My\First\Use\Class;', $generated); } /** * @group 4990 */ public function testAddOneUseWithAliasTwiceOnlyAddsOne() { $classGenerator = new ClassGenerator(); $classGenerator->setName('My\Class'); $classGenerator->addUse('My\First\Use\Class', 'MyAlias'); $classGenerator->addUse('My\First\Use\Class', 'MyAlias'); $generated = $classGenerator->generate(); self::assertCount(1, $classGenerator->getUses()); self::assertStringContainsString('use My\First\Use\Class as MyAlias;', $generated); } public function testCreateFromArrayWithDocBlockFromArray() { $classGenerator = ClassGenerator::fromArray([ 'name' => 'SampleClass', 'docblock' => [ 'shortdescription' => 'foo', ], ]); $docBlock = $classGenerator->getDocBlock(); self::assertInstanceOf(DocBlockGenerator::class, $docBlock); } public function testCreateFromArrayWithDocBlockInstance() { $classGenerator = ClassGenerator::fromArray([ 'name' => 'SampleClass', 'docblock' => new DocBlockGenerator('foo'), ]); $docBlock = $classGenerator->getDocBlock(); self::assertInstanceOf(DocBlockGenerator::class, $docBlock); } public function testExtendedClassProperies() { $reflClass = new ClassReflection(TestAsset\ExtendedClassWithProperties::class); $classGenerator = ClassGenerator::fromReflection($reflClass); $code = $classGenerator->generate(); self::assertStringContainsString('publicExtendedClassProperty', $code); self::assertStringContainsString('protectedExtendedClassProperty', $code); self::assertStringContainsString('privateExtendedClassProperty', $code); self::assertStringNotContainsString('publicClassProperty', $code); self::assertStringNotContainsString('protectedClassProperty', $code); self::assertStringNotContainsString('privateClassProperty', $code); } public function testHasMethodInsensitive() { $classGenerator = new ClassGenerator(); $classGenerator->addMethod('methodOne'); self::assertTrue($classGenerator->hasMethod('methodOne')); self::assertTrue($classGenerator->hasMethod('MethoDonE')); } public function testRemoveMethodInsensitive() { $classGenerator = new ClassGenerator(); $classGenerator->addMethod('methodOne'); $classGenerator->removeMethod('METHODONe'); self::assertFalse($classGenerator->hasMethod('methodOne')); } public function testGenerateClassAndAddMethod() { $classGenerator = new ClassGenerator(); $classGenerator->setName('MyClass'); $classGenerator->addMethod('methodOne'); $expected = <<generate(); self::assertEquals($expected, $output); } /** * @group 6274 */ public function testCanAddConstant() { $classGenerator = new ClassGenerator(); $classGenerator->setName('My\Class'); $classGenerator->addConstant('x', 'value'); self::assertTrue($classGenerator->hasConstant('x')); $constant = $classGenerator->getConstant('x'); self::assertInstanceOf(PropertyGenerator::class, $constant); self::assertTrue($constant->isConst()); self::assertEquals('value', $constant->getDefaultValue()->getValue()); } /** * @group 6274 */ public function testCanAddConstantsWithArrayOfGenerators() { $classGenerator = new ClassGenerator(); $classGenerator->addConstants([ new PropertyGenerator('x', 'value1', PropertyGenerator::FLAG_CONSTANT), new PropertyGenerator('y', 'value2', PropertyGenerator::FLAG_CONSTANT), ]); self::assertCount(2, $classGenerator->getConstants()); self::assertEquals('value1', $classGenerator->getConstant('x')->getDefaultValue()->getValue()); self::assertEquals('value2', $classGenerator->getConstant('y')->getDefaultValue()->getValue()); } /** * @group 6274 */ public function testCanAddConstantsWithArrayOfKeyValues() { $classGenerator = new ClassGenerator(); $classGenerator->addConstants([ ['name' => 'x', 'value' => 'value1'], ['name' => 'y', 'value' => 'value2'], ]); self::assertCount(2, $classGenerator->getConstants()); self::assertEquals('value1', $classGenerator->getConstant('x')->getDefaultValue()->getValue()); self::assertEquals('value2', $classGenerator->getConstant('y')->getDefaultValue()->getValue()); } /** * @group 6274 */ public function testAddConstantThrowsExceptionWithInvalidName() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $classGenerator->addConstant([], 'value1'); } public function testAddConstantThrowsExceptionWithEmptyConstantName() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $classGenerator->addConstant('', 'value'); } public function testAddConstantAcceptsMixedScalars() { $classGenerator = new ClassGenerator(); $classGenerator->addConstant('a', 'v'); $classGenerator->addConstant('b', 123); $classGenerator->addConstant('c', 123.456); $classGenerator->addConstant('d', []); $classGenerator->addConstant('e', ['v1' => 'v2']); $classGenerator->addConstant('f', ['v1' => ['v2' => 'v3']]); $classGenerator->addConstant('g', null); self::assertEquals('v', $classGenerator->getConstant('a')->getDefaultValue()->getValue()); self::assertEquals(123, $classGenerator->getConstant('b')->getDefaultValue()->getValue()); self::assertEquals(123.456, $classGenerator->getConstant('c')->getDefaultValue()->getValue()); self::assertEquals([], $classGenerator->getConstant('d')->getDefaultValue()->getValue()); self::assertEquals(['v1' => 'v2'], $classGenerator->getConstant('e')->getDefaultValue()->getValue()); self::assertEquals(['v1' => ['v2' => 'v3']], $classGenerator->getConstant('f')->getDefaultValue()->getValue()); self::assertEquals(null, $classGenerator->getConstant('g')->getDefaultValue()->getValue()); } public function testAddConstantRejectsObjectConstantValue() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $classGenerator->addConstant('a', new \stdClass()); } public function testAddConstantRejectsResourceConstantValue() { $classGenerator = new ClassGenerator(); $resource = fopen('php://memory', 'r'); try { $classGenerator->addConstant('a', $resource); $this->fail('Not supposed to be reached'); } catch (InvalidArgumentException $e) { self::assertEmpty($classGenerator->getConstants()); } finally { fclose($resource); } } public function testAddConstantRejectsArrayWithInvalidNestedValue() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $classGenerator->addConstant('a', [new \stdClass()]); } /** * @group 6274 */ public function testAddConstantThrowsExceptionOnDuplicate() { $classGenerator = new ClassGenerator(); $classGenerator->addConstant('x', 'value1'); $this->expectException('InvalidArgumentException'); $classGenerator->addConstant('x', 'value1'); } public function testRemoveConstant() { $classGenerator = new ClassGenerator(); $classGenerator->addConstant('constantOne', 'foo'); self::assertTrue($classGenerator->hasConstant('constantOne')); $classGenerator->removeConstant('constantOne'); self::assertFalse($classGenerator->hasConstant('constantOne')); } /** * @group 6274 */ public function testAddPropertyIsBackwardsCompatibleWithConstants() { $classGenerator = new ClassGenerator(); $classGenerator->addProperty('x', 'value1', PropertyGenerator::FLAG_CONSTANT); self::assertEquals('value1', $classGenerator->getConstant('x')->getDefaultValue()->getValue()); } /** * @group 6274 */ public function testAddPropertiesIsBackwardsCompatibleWithConstants() { $constants = [ new PropertyGenerator('x', 'value1', PropertyGenerator::FLAG_CONSTANT), new PropertyGenerator('y', 'value2', PropertyGenerator::FLAG_CONSTANT), ]; $classGenerator = new ClassGenerator(); $classGenerator->addProperties($constants); self::assertCount(2, $classGenerator->getConstants()); self::assertEquals('value1', $classGenerator->getConstant('x')->getDefaultValue()->getValue()); self::assertEquals('value2', $classGenerator->getConstant('y')->getDefaultValue()->getValue()); } /** * @group 6274 */ public function testConstantsAddedFromReflection() { $reflector = new ClassReflection(TestAsset\TestClassWithManyProperties::class); $classGenerator = ClassGenerator::fromReflection($reflector); $constant = $classGenerator->getConstant('FOO'); self::assertEquals('foo', $constant->getDefaultValue()->getValue()); } /** * @group 6274 */ public function testClassCanBeGeneratedWithConstantAndPropertyWithSameName() { $reflector = new ClassReflection(TestAsset\TestSampleSingleClass::class); $classGenerator = ClassGenerator::fromReflection($reflector); $classGenerator->addProperty('fooProperty', true, PropertyGenerator::FLAG_PUBLIC); $classGenerator->addConstant('fooProperty', 'duplicate'); $contents = <<<'CODE' namespace ZendTest\Code\Generator\TestAsset; /** * class docblock */ class TestSampleSingleClass { public const fooProperty = 'duplicate'; public $fooProperty = true; /** * Enter description here... * * @return bool */ public function someMethod() { /* test test */ } /** * Enter description here... * * @return bool */ protected function withParamsAndReturnType($mixed, array $array, ?callable $callable = null, ?int $int = 0) : bool { /* test test */ return true; } } CODE; self::assertEquals($classGenerator->generate(), $contents); } /** * @group 6253 */ public function testHereDoc() { $reflector = new ClassReflection(TestAsset\TestClassWithHeredoc::class); $classGenerator = new ClassGenerator(); $methods = $reflector->getMethods(); $classGenerator->setName('OutputClass'); foreach ($methods as $method) { $methodGenerator = MethodGenerator::fromReflection($method); $classGenerator->addMethodFromGenerator($methodGenerator); } $contents = <<< 'CODE' class OutputClass { public function someFunction() { $output = <<< END Fix it, fix it! Fix it, fix it! Fix it, fix it! END; } } CODE; self::assertEquals($contents, $classGenerator->generate()); } public function testCanAddTraitWithString() { $classGenerator = new ClassGenerator(); $classGenerator->addTrait('myTrait'); self::assertTrue($classGenerator->hasTrait('myTrait')); } public function testCanAddTraitWithArray() { $classGenerator = new ClassGenerator(); $classGenerator->addTrait(['traitName' => 'myTrait']); self::assertTrue($classGenerator->hasTrait('myTrait')); } public function testCanRemoveTrait() { $classGenerator = new ClassGenerator(); $classGenerator->addTrait(['traitName' => 'myTrait']); self::assertTrue($classGenerator->hasTrait('myTrait')); $classGenerator->removeTrait('myTrait'); self::assertFalse($classGenerator->hasTrait('myTrait')); } public function testCanGetTraitsMethod() { $classGenerator = new ClassGenerator(); $classGenerator->addTraits(['myTrait', 'hisTrait']); $traits = $classGenerator->getTraits(); self::assertContains('myTrait', $traits); self::assertContains('hisTrait', $traits); } public function testCanAddTraitAliasWithString() { $classGenerator = new ClassGenerator(); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitAlias('myTrait::method', 'useMe', ReflectionMethod::IS_PRIVATE); $aliases = $classGenerator->getTraitAliases(); self::assertArrayHasKey('myTrait::method', $aliases); self::assertEquals('useMe', $aliases['myTrait::method']['alias']); self::assertEquals(ReflectionMethod::IS_PRIVATE, $aliases['myTrait::method']['visibility']); } public function testCanAddTraitAliasWithArray() { $classGenerator = new ClassGenerator(); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitAlias([ 'traitName' => 'myTrait', 'method' => 'method', ], 'useMe', ReflectionMethod::IS_PRIVATE); $aliases = $classGenerator->getTraitAliases(); self::assertArrayHasKey('myTrait::method', $aliases); self::assertEquals('useMe', $aliases['myTrait::method']['alias']); self::assertEquals(ReflectionMethod::IS_PRIVATE, $aliases['myTrait::method']['visibility']); } public function testAddTraitAliasExceptionInvalidMethodFormat() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid Format: $method must be in the format of trait::method'); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitAlias('method', 'useMe'); } public function testAddTraitAliasExceptionInvalidMethodTraitDoesNotExist() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid trait: Trait does not exists on this class'); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitAlias('unknown::method', 'useMe'); } public function testAddTraitAliasExceptionMethodAlreadyExists() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid Alias: Method name already exists on this class.'); $classGenerator->addMethod('methodOne'); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitAlias('myTrait::method', 'methodOne'); } public function testAddTraitAliasExceptionInvalidVisibilityValue() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage( 'Invalid Type: $visibility must of ReflectionMethod::IS_PUBLIC,' . ' ReflectionMethod::IS_PRIVATE or ReflectionMethod::IS_PROTECTED' ); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitAlias('myTrait::method', 'methodOne', 'public'); } public function testAddTraitAliasExceptionInvalidAliasArgument() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid Alias: $alias must be a string or array.'); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitAlias('myTrait::method', new ClassGenerator(), 'public'); } public function testCanAddTraitOverride() { $classGenerator = new ClassGenerator(); $classGenerator->addTraits(['myTrait', 'histTrait']); $classGenerator->addTraitOverride('myTrait::foo', 'hisTrait'); $overrides = $classGenerator->getTraitOverrides(); self::assertCount(1, $overrides); self::assertEquals('myTrait::foo', key($overrides)); self::assertEquals('hisTrait', $overrides['myTrait::foo'][0]); } public function testCanAddMultipleTraitOverrides() { $classGenerator = new ClassGenerator(); $classGenerator->addTraits(['myTrait', 'histTrait', 'thatTrait']); $classGenerator->addTraitOverride('myTrait::foo', ['hisTrait', 'thatTrait']); $overrides = $classGenerator->getTraitOverrides(); self::assertCount(2, $overrides['myTrait::foo']); self::assertEquals('thatTrait', $overrides['myTrait::foo'][1]); } public function testAddTraitOverrideExceptionInvalidMethodFormat() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid Format: $method must be in the format of trait::method'); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitOverride('method', 'useMe'); } public function testAddTraitOverrideExceptionInvalidMethodTraitDoesNotExist() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid trait: Trait does not exists on this class'); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitOverride('unknown::method', 'useMe'); } public function testAddTraitOverrideExceptionInvalidTraitName() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing required argument "traitName" for $method'); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitOverride(['method' => 'foo'], 'test'); } public function testAddTraitOverrideExceptionInvalidTraitToReplaceArgument() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid Argument: $traitToReplace must be a string or array of strings'); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitOverride('myTrait::method', ['methodOne', 4]); } public function testAddTraitOverrideExceptionInvalidMethodArgInArray() { $classGenerator = new ClassGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing required argument "method" for $method'); $classGenerator->addTrait('myTrait'); $classGenerator->addTraitOverride(['traitName' => 'myTrait'], 'test'); } public function testCanRemoveTraitOverride() { $classGenerator = new ClassGenerator(); $classGenerator->addTraits(['myTrait', 'histTrait', 'thatTrait']); $classGenerator->addTraitOverride('myTrait::foo', ['hisTrait', 'thatTrait']); $overrides = $classGenerator->getTraitOverrides(); self::assertCount(2, $overrides['myTrait::foo']); $classGenerator->removeTraitOverride('myTrait::foo', 'hisTrait'); $overrides = $classGenerator->getTraitOverrides(); self::assertCount(1, $overrides['myTrait::foo']); self::assertEquals('thatTrait', $overrides['myTrait::foo'][1]); } public function testCanRemoveAllTraitOverrides() { $classGenerator = new ClassGenerator(); $classGenerator->addTraits(['myTrait', 'histTrait', 'thatTrait']); $classGenerator->addTraitOverride('myTrait::foo', ['hisTrait', 'thatTrait']); $overrides = $classGenerator->getTraitOverrides(); self::assertCount(2, $overrides['myTrait::foo']); $classGenerator->removeTraitOverride('myTrait::foo'); $overrides = $classGenerator->getTraitOverrides(); self::assertCount(0, $overrides); } /** * @group generate */ public function testUseTraitGeneration() { $classGenerator = new ClassGenerator(); $classGenerator->setName('myClass'); $classGenerator->addTrait('myTrait'); $classGenerator->addTrait('hisTrait'); $classGenerator->addTrait('thatTrait'); $output = <<<'CODE' class myClass { use myTrait, hisTrait, thatTrait; } CODE; self::assertEquals($classGenerator->generate(), $output); } /** * @group generate */ public function testTraitGenerationWithAliasesAndOverrides() { $classGenerator = new ClassGenerator(); $classGenerator->setName('myClass'); $classGenerator->addTrait('myTrait'); $classGenerator->addTrait('hisTrait'); $classGenerator->addTrait('thatTrait'); $classGenerator->addTraitAlias('hisTrait::foo', 'test', ReflectionMethod::IS_PUBLIC); $classGenerator->addTraitOverride('myTrait::bar', ['hisTrait', 'thatTrait']); $output = <<<'CODE' class myClass { use myTrait, hisTrait, thatTrait { hisTrait::foo as public test; myTrait::bar insteadof hisTrait; myTrait::bar insteadof thatTrait; } } CODE; self::assertEquals($classGenerator->generate(), $output); } public function testGenerateWithFinalFlag() { $classGenerator = ClassGenerator::fromArray([ 'name' => 'SomeClass', 'flags' => ClassGenerator::FLAG_FINAL, ]); $expectedOutput = <<generate(); self::assertEquals($expectedOutput, $output, $output); } public function testCorrectExtendNames() { $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setNamespaceName('SomeNamespace'); $classGenerator->addUse(NameInformation::class); $classGenerator->setExtendedClass(NameInformation::class); self::assertStringContainsString('class ClassName extends NameInformation', $classGenerator->generate()); } /** * @group 75 */ public function testCorrectlyExtendsFullyQualifiedParentClass() { $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setNamespaceName('SomeNamespace'); $classGenerator->setExtendedClass('DateTime'); self::assertStringContainsString('class ClassName extends \DateTime', $classGenerator->generate()); } /** * @group 75 */ public function testCorrectlyExtendsRelativeParentClass() { $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setExtendedClass('DateTime'); self::assertStringContainsString('class ClassName extends DateTime', $classGenerator->generate()); } /** * @group 75 */ public function testCorrectExtendNamesFromGlobalNamespace() { $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setNamespaceName('SomeNamespace'); $classGenerator->setExtendedClass(DateTime::class); self::assertStringContainsString('class ClassName extends \DateTime', $classGenerator->generate()); $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setExtendedClass(DateTime::class); self::assertStringContainsString('class ClassName extends DateTime', $classGenerator->generate()); } public function testCorrectlyExtendsProvidedAliasIfUseAliasExists() { $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setNamespaceName('SomeNamespace'); $classGenerator->addUse('Foo\\Bar', 'BarAlias'); $classGenerator->setExtendedClass('BarAlias'); $generated = $classGenerator->generate(); self::assertStringContainsString('class ClassName extends BarAlias', $generated); } public function testCorrectlyExtendsProvidedNamespaceAliasIfUseAliasExistsForNamespace() { $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setNamespaceName('SomeNamespace'); $classGenerator->addUse('Foo\\Bar', 'BarAlias'); $classGenerator->setExtendedClass('BarAlias\\FooBar'); $generated = $classGenerator->generate(); self::assertStringContainsString('class ClassName extends BarAlias\\FooBar', $generated); } public function testCorrectlyExtendsAliasOfProvidedFQCNIfUseAliasExists() { $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setNamespaceName('SomeNamespace'); $classGenerator->addUse('Foo\\Bar', 'BarAlias'); $classGenerator->setExtendedClass('Foo\\Bar'); $generated = $classGenerator->generate(); self::assertStringContainsString('class ClassName extends BarAlias', $generated); } public function testCorrectlyExtendsWithNamespaceAliasOfProvidedFQCNIfUseAliasExistsForNamespace() { $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setNamespaceName('SomeNamespace'); $classGenerator->addUse('Foo\\Bar', 'BarAlias'); $classGenerator->setExtendedClass('Foo\\Bar\\FooBar'); $generated = $classGenerator->generate(); self::assertStringContainsString('class ClassName extends BarAlias\\FooBar', $generated); } public function testCorrectImplementNames() { $classGenerator = new ClassGenerator(); $classGenerator->setName('ClassName'); $classGenerator->setNamespaceName('SomeNamespace'); $classGenerator->addUse(GeneratorInterface::class); $classGenerator->setImplementedInterfaces([ 'SomeNamespace\ClassInterface', GeneratorInterface::class, 'Iteratable', ]); $expected = 'class ClassName implements ClassInterface, GeneratorInterface, \Iteratable'; self::assertStringContainsString($expected, $classGenerator->generate()); } } php-zend-code-3.4.1/test/Generator/DocBlock/000077500000000000000000000000001357431215700205515ustar00rootroot00000000000000php-zend-code-3.4.1/test/Generator/DocBlock/Tag/000077500000000000000000000000001357431215700212645ustar00rootroot00000000000000php-zend-code-3.4.1/test/Generator/DocBlock/Tag/AuthorTagTest.php000066400000000000000000000050371357431215700245400ustar00rootroot00000000000000tag = new AuthorTag(); $this->tagmanager = new TagManager(); $this->tagmanager->initializeDefaultTags(); } protected function tearDown() : void { $this->tag = null; $this->tagmanager = null; } public function testGetterAndSetterPersistValue() { $this->tag->setAuthorName('Foo'); $this->tag->setAuthorEmail('Bar'); self::assertEquals('Foo', $this->tag->getAuthorName()); self::assertEquals('Bar', $this->tag->getAuthorEmail()); } public function testParamProducesCorrectDocBlockLine() { $this->tag->setAuthorName('foo'); $this->tag->setAuthorEmail('string'); self::assertEquals('@author foo ', $this->tag->generate()); } public function testNameIsCorrect() { self::assertEquals('author', $this->tag->getName()); } public function testConstructorWithOptions() { $this->tag->setOptions([ 'authorEmail' => 'string', 'authorName' => 'foo', ]); $tagWithOptionsFromConstructor = new AuthorTag('foo', 'string'); self::assertEquals($this->tag->generate(), $tagWithOptionsFromConstructor->generate()); } public function testCreatingTagFromReflection() { $docreflection = new DocBlockReflection('/** @author Mister Miller '); $reflectionTag = $docreflection->getTag('author'); /** @var AuthorTag $tag */ $tag = $this->tagmanager->createTagFromReflection($reflectionTag); self::assertInstanceOf(AuthorTag::class, $tag); self::assertEquals('Mister Miller', $tag->getAuthorName()); self::assertEquals('mister.miller@zend.com', $tag->getAuthorEmail()); } } php-zend-code-3.4.1/test/Generator/DocBlock/Tag/GenericTagTest.php000066400000000000000000000045101357431215700246450ustar00rootroot00000000000000tag = new GenericTag(); $this->tagmanager = new TagManager(); $this->tagmanager->initializeDefaultTags(); } protected function tearDown() : void { $this->tag = null; $this->tagmanager = null; } public function testGetterAndSetterPersistValue() { $this->tag->setName('var'); $this->tag->setContent('string'); self::assertEquals('var', $this->tag->getName()); self::assertEquals('string', $this->tag->getContent()); } public function testParamProducesCorrectDocBlockLine() { $this->tag->setName('var'); $this->tag->setContent('string'); self::assertEquals('@var string', $this->tag->generate()); } public function testConstructorWithOptions() { $this->tag->setOptions([ 'name' => 'var', 'content' => 'string', ]); $tagWithOptionsFromConstructor = new GenericTag('var', 'string'); self::assertEquals($this->tag->generate(), $tagWithOptionsFromConstructor->generate()); } public function testCreatingTagFromReflection() { $docreflection = new DocBlockReflection('/** @global string'); $reflectionTag = $docreflection->getTag('global'); /** @var GenericTag $tag */ $tag = $this->tagmanager->createTagFromReflection($reflectionTag); self::assertInstanceOf(GenericTag::class, $tag); self::assertEquals('global', $tag->getName()); self::assertEquals('string', $tag->getContent()); } } php-zend-code-3.4.1/test/Generator/DocBlock/Tag/LicenseTagTest.php000066400000000000000000000047601357431215700246620ustar00rootroot00000000000000tag = new LicenseTag(); $this->tagmanager = new TagManager(); $this->tagmanager->initializeDefaultTags(); } protected function tearDown() : void { $this->tag = null; $this->tagmanager = null; } public function testGetterAndSetterPersistValue() { $this->tag->setUrl('foo'); $this->tag->setLicenseName('bar'); self::assertEquals('foo', $this->tag->getUrl()); self::assertEquals('bar', $this->tag->getLicenseName()); } public function testNameIsCorrect() { self::assertEquals('license', $this->tag->getName()); } public function testLicenseProducesCorrectDocBlockLine() { $this->tag->setUrl('foo'); $this->tag->setLicenseName('bar bar bar'); self::assertEquals('@license foo bar bar bar', $this->tag->generate()); } public function testConstructorWithOptions() { $this->tag->setOptions([ 'url' => 'foo', 'licenseName' => 'bar', ]); $tagWithOptionsFromConstructor = new LicenseTag('foo', 'bar'); self::assertEquals($this->tag->generate(), $tagWithOptionsFromConstructor->generate()); } public function testCreatingTagFromReflection() { $docreflection = new DocBlockReflection('/** @license http://zend.com License'); $reflectionTag = $docreflection->getTag('license'); /** @var LicenseTag $tag */ $tag = $this->tagmanager->createTagFromReflection($reflectionTag); self::assertInstanceOf(LicenseTag::class, $tag); self::assertEquals('http://zend.com', $tag->getUrl()); self::assertEquals('License', $tag->getLicenseName()); } } php-zend-code-3.4.1/test/Generator/DocBlock/Tag/MethodTagTest.php000066400000000000000000000060171357431215700245150ustar00rootroot00000000000000tag = new MethodTag(); $this->tagmanager = new TagManager(); $this->tagmanager->initializeDefaultTags(); } protected function tearDown() : void { $this->tag = null; $this->tagmanager = null; } public function testGetterAndSetterPersistValue() { $this->tag->setIsStatic(true); $this->tag->setMethodName('method'); self::assertEquals(true, $this->tag->isStatic()); self::assertEquals('method', $this->tag->getMethodName()); } public function testGetterForMethodNameTrimsCorrectly() { $this->tag->setMethodName('()method()'); self::assertEquals('()method', $this->tag->getMethodName()); } public function testNameIsCorrect() { self::assertEquals('method', $this->tag->getName()); } public function testParamProducesCorrectDocBlockLine() { $this->tag->setIsStatic(true); $this->tag->setMethodName('method'); $this->tag->setTypes('int'); $this->tag->setDescription('method(string $a)'); self::assertEquals('@method static int method() method(string $a)', $this->tag->generate()); } public function testConstructorWithOptions() { $this->tag->setOptions([ 'isStatic' => true, 'methodName' => 'method', 'types' => ['string'], 'description' => 'description', ]); $tagWithOptionsFromConstructor = new MethodTag('method', ['string'], 'description', true); self::assertEquals($this->tag->generate(), $tagWithOptionsFromConstructor->generate()); } public function testCreatingTagFromReflection() { $docreflection = new DocBlockReflection('/** @method static int method() method(int $a)'); $reflectionTag = $docreflection->getTag('method'); /** @var MethodTag $tag */ $tag = $this->tagmanager->createTagFromReflection($reflectionTag); self::assertInstanceOf(MethodTag::class, $tag); self::assertEquals(true, $tag->isStatic()); self::assertEquals('int', $tag->getTypesAsString()); self::assertEquals('method', $tag->getMethodName()); self::assertEquals('method(int $a)', $tag->getDescription()); } } php-zend-code-3.4.1/test/Generator/DocBlock/Tag/ParamTagTest.php000066400000000000000000000054031357431215700243330ustar00rootroot00000000000000tag = new ParamTag(); $this->tagmanager = new TagManager(); $this->tagmanager->initializeDefaultTags(); } protected function tearDown() : void { $this->tag = null; $this->tagmanager = null; } public function testGetterAndSetterPersistValue() { $this->tag->setVariableName('Foo'); self::assertEquals('Foo', $this->tag->getVariableName()); } public function testGetterForVariableNameTrimsCorrectly() { $this->tag->setVariableName('$param$'); self::assertEquals('param$', $this->tag->getVariableName()); } public function testNameIsCorrect() { self::assertEquals('param', $this->tag->getName()); } public function testParamProducesCorrectDocBlockLine() { $this->tag->setVariableName('foo'); $this->tag->setTypes('string|null'); $this->tag->setDescription('description'); self::assertEquals('@param string|null $foo description', $this->tag->generate()); } public function testConstructorWithOptions() { $this->tag->setOptions([ 'variableName' => 'foo', 'types' => ['string'], 'description' => 'description', ]); $tagWithOptionsFromConstructor = new ParamTag('foo', ['string'], 'description'); self::assertEquals($this->tag->generate(), $tagWithOptionsFromConstructor->generate()); } public function testCreatingTagFromReflection() { $docreflection = new DocBlockReflection('/** @param int $foo description'); $reflectionTag = $docreflection->getTag('param'); /** @var ParamTag $tag */ $tag = $this->tagmanager->createTagFromReflection($reflectionTag); self::assertInstanceOf(ParamTag::class, $tag); self::assertEquals('foo', $tag->getVariableName()); self::assertEquals('description', $tag->getDescription()); self::assertEquals('int', $tag->getTypesAsString()); } } php-zend-code-3.4.1/test/Generator/DocBlock/Tag/PropertyTagTest.php000066400000000000000000000055021357431215700251170ustar00rootroot00000000000000tag = new PropertyTag(); $this->tagmanager = new TagManager(); $this->tagmanager->initializeDefaultTags(); } protected function tearDown() : void { $this->tag = null; $this->tagmanager = null; } public function testGetterAndSetterPersistValue() { $this->tag->setPropertyName('property'); self::assertEquals('property', $this->tag->getPropertyName()); } public function testGetterForVariableNameTrimsCorrectly() { $this->tag->setPropertyName('$property$'); self::assertEquals('property$', $this->tag->getPropertyName()); } public function testNameIsCorrect() { self::assertEquals('property', $this->tag->getName()); } public function testParamProducesCorrectDocBlockLine() { $this->tag->setPropertyName('property'); $this->tag->setTypes('string[]'); $this->tag->setDescription('description'); self::assertEquals('@property string[] $property description', $this->tag->generate()); } public function testConstructorWithOptions() { $this->tag->setOptions([ 'propertyName' => 'property', 'types' => ['string'], 'description' => 'description', ]); $tagWithOptionsFromConstructor = new PropertyTag('property', ['string'], 'description'); self::assertEquals($this->tag->generate(), $tagWithOptionsFromConstructor->generate()); } public function testCreatingTagFromReflection() { $docreflection = new DocBlockReflection('/** @property int $foo description'); $reflectionTag = $docreflection->getTag('property'); /** @var PropertyTag $tag */ $tag = $this->tagmanager->createTagFromReflection($reflectionTag); self::assertInstanceOf(PropertyTag::class, $tag); self::assertEquals('foo', $tag->getPropertyName()); self::assertEquals('description', $tag->getDescription()); self::assertEquals('int', $tag->getTypesAsString()); } } php-zend-code-3.4.1/test/Generator/DocBlock/Tag/ReturnTagTest.php000066400000000000000000000036171357431215700245570ustar00rootroot00000000000000tag = new ReturnTag(); $this->tagmanager = new TagManager(); $this->tagmanager->initializeDefaultTags(); } protected function tearDown() : void { $this->tag = null; $this->tagmanager = null; } public function testNameIsCorrect() { self::assertEquals('return', $this->tag->getName()); } public function testReturnProducesCorrectDocBlockLine() { $this->tag->setTypes('string|int'); $this->tag->setDescription('bar bar bar'); self::assertEquals('@return string|int bar bar bar', $this->tag->generate()); } public function testCreatingTagFromReflection() { $docreflection = new DocBlockReflection('/** @return int The return'); $reflectionTag = $docreflection->getTag('return'); /** @var ReturnTag $tag */ $tag = $this->tagmanager->createTagFromReflection($reflectionTag); self::assertInstanceOf(ReturnTag::class, $tag); self::assertEquals('The return', $tag->getDescription()); self::assertEquals('int', $tag->getTypesAsString()); } } php-zend-code-3.4.1/test/Generator/DocBlock/Tag/ThrowsTagTest.php000066400000000000000000000037041357431215700245630ustar00rootroot00000000000000tag = new ThrowsTag(); $this->tagmanager = new TagManager(); $this->tagmanager->initializeDefaultTags(); } protected function tearDown() : void { $this->tag = null; $this->tagmanager = null; } public function testNameIsCorrect() { self::assertEquals('throws', $this->tag->getName()); } public function testParamProducesCorrectDocBlockLine() { $this->tag->setTypes('Exception\\MyException'); $this->tag->setDescription('description'); self::assertEquals('@throws Exception\\MyException description', $this->tag->generate()); } public function testCreatingTagFromReflection() { $docreflection = new DocBlockReflection('/** @throws Exception\Invalid description'); $reflectionTag = $docreflection->getTag('throws'); /** @var ThrowsTag $tag */ $tag = $this->tagmanager->createTagFromReflection($reflectionTag); self::assertInstanceOf(ThrowsTag::class, $tag); self::assertEquals('description', $tag->getDescription()); self::assertEquals('Exception\Invalid', $tag->getTypesAsString()); } } php-zend-code-3.4.1/test/Generator/DocBlock/Tag/TypableTagTest.php000066400000000000000000000043731357431215700247000ustar00rootroot00000000000000tag = new TypeableTag(); } protected function tearDown() : void { $this->tag = null; } public function testGetterAndSetterPersistValue() { $this->tag->setTypes(['string', 'null']); $this->tag->setDescription('Description'); self::assertEquals(['string', 'null'], $this->tag->getTypes()); self::assertEquals('Description', $this->tag->getDescription()); } public function testGetterForTypesAsStringWithSingleType() { $this->tag->setTypes(['string']); self::assertEquals('string', $this->tag->getTypesAsString()); } public function testGetterForTypesAsStringWithSingleTypeAndDelimiter() { $this->tag->setTypes(['string']); self::assertEquals('string', $this->tag->getTypesAsString('/')); } public function testGetterForTypesAsStringWithMultipleTypes() { $this->tag->setTypes(['string', 'null']); self::assertEquals('string|null', $this->tag->getTypesAsString()); } public function testGetterForTypesAsStringWithMultipleTypesAndDelimiter() { $this->tag->setTypes(['string', 'null']); self::assertEquals('string/null', $this->tag->getTypesAsString('/')); } public function testConstructorWithOptions() { $this->tag->setOptions([ 'types' => ['string', 'null'], 'description' => 'description', ]); $tagWithOptionsFromConstructor = new TypeableTag(['string', 'null'], 'description'); self::assertEquals($this->tag->generate(), $tagWithOptionsFromConstructor->generate()); } } php-zend-code-3.4.1/test/Generator/DocBlock/Tag/VarTagTest.php000066400000000000000000000054741357431215700240330ustar00rootroot00000000000000tag = new VarTag(); $this->tagManager = new TagManager(); $this->tagManager->initializeDefaultTags(); } public function testGetterAndSetterPersistValue() : void { $tag = new VarTag('variable'); self::assertSame('variable', $tag->getVariableName()); } public function testGetterForVariableNameTrimsCorrectly() : void { $this->tag->setVariableName('$variable$'); $this->assertEquals('variable$', $this->tag->getVariableName()); } public function testNameIsCorrect() : void { $this->assertEquals('var', $this->tag->getName()); } public function testParamProducesCorrectDocBlockLine() : void { $this->tag->setVariableName('variable'); $this->tag->setTypes('string[]'); $this->tag->setDescription('description'); $this->assertEquals('@var string[] $variable description', $this->tag->generate()); } public function testConstructorWithOptions() : void { $this->tag->setOptions([ 'variableName' => 'foo', 'types' => ['string'], 'description' => 'description', ]); $tagWithOptionsFromConstructor = new VarTag('foo', ['string'], 'description'); $this->assertEquals($this->tag->generate(), $tagWithOptionsFromConstructor->generate()); } public function testCreatingTagFromReflection() : void { $reflectionTag = (new DocBlockReflection('/** @var int $foo description')) ->getTag('var'); self::assertInstanceOf(ReflectionVarTag::class, $reflectionTag); /** @var VarTag $tag */ $tag = $this->tagManager->createTagFromReflection($reflectionTag); $this->assertInstanceOf(VarTag::class, $tag); $this->assertEquals('foo', $tag->getVariableName()); $this->assertEquals('description', $tag->getDescription()); $this->assertEquals('int', $tag->getTypesAsString()); } } php-zend-code-3.4.1/test/Generator/DocBlockGeneratorTest.php000066400000000000000000000151561357431215700240010ustar00rootroot00000000000000docBlockGenerator = $this->docBlockGenerator = new DocBlockGenerator(); $reflectionDocBlock = new DocBlockReflection( '/** * Short Description * Long Description * @param string $foo comment * @author Zend * @license http://license The License * @return int */' ); $this->reflectionDocBlockGenerator = DocBlockGenerator::fromReflection($reflectionDocBlock); } public function testCanPassTagsToConstructor() { $docBlockGenerator = new DocBlockGenerator(null, null, [ ['name' => 'foo'], ]); $tags = $docBlockGenerator->getTags(); self::assertCount(1, $tags); self::assertEquals('foo', $tags[0]->getName()); } public function testShortDescriptionGetterAndSetter() { $this->docBlockGenerator->setShortDescription('Short Description'); self::assertEquals('Short Description', $this->docBlockGenerator->getShortDescription()); } public function testLongDescriptionGetterAndSetter() { $this->docBlockGenerator->setLongDescription('Long Description'); self::assertEquals('Long Description', $this->docBlockGenerator->getLongDescription()); } public function testTagGettersAndSetters() { $paramTag = new Tag\ParamTag(); $paramTag->setDatatype('string'); $returnTag = new Tag\ReturnTag(); $returnTag->setDatatype('int'); $this->docBlockGenerator->setTag(['name' => 'blah']); $this->docBlockGenerator->setTag($paramTag); $this->docBlockGenerator->setTag($returnTag); self::assertCount(3, $this->docBlockGenerator->getTags()); $target = <<docBlockGenerator->generate()); } public function testGenerationOfDocBlock() { $this->docBlockGenerator->setShortDescription('@var Foo this is foo bar'); $expected = '/**' . DocBlockGenerator::LINE_FEED . ' * @var Foo this is foo bar' . DocBlockGenerator::LINE_FEED . ' */' . DocBlockGenerator::LINE_FEED; self::assertEquals($expected, $this->docBlockGenerator->generate()); } public function testCreateFromArray() { $docBlock = DocBlockGenerator::fromArray([ 'shortdescription' => 'foo', 'longdescription' => 'bar', 'tags' => [ [ 'name' => 'foo', 'description' => 'bar', ], ], ]); self::assertEquals('foo', $docBlock->getShortDescription()); self::assertEquals('bar', $docBlock->getLongDescription()); self::assertCount(1, $docBlock->getTags()); } /** * @group #3753 */ public function testGenerateWordWrapIsEnabledByDefault() { $largeStr = '@var This is a very large string that will be wrapped if it contains more than 80 characters'; $this->docBlockGenerator->setLongDescription($largeStr); $expected = '/**' . DocBlockGenerator::LINE_FEED . ' * @var This is a very large string that will be wrapped if it contains more than' . DocBlockGenerator::LINE_FEED . ' * 80 characters' . DocBlockGenerator::LINE_FEED . ' */' . DocBlockGenerator::LINE_FEED; self::assertEquals($expected, $this->docBlockGenerator->generate()); } /** * @group #3753 */ public function testGenerateWithWordWrapDisabled() { $largeStr = '@var This is a very large string that will not be wrapped if it contains more than 80 characters'; $this->docBlockGenerator->setLongDescription($largeStr); $this->docBlockGenerator->setWordWrap(false); $expected = '/**' . DocBlockGenerator::LINE_FEED . ' * @var This is a very large string that will not be wrapped if it contains more than' . ' 80 characters' . DocBlockGenerator::LINE_FEED . ' */' . DocBlockGenerator::LINE_FEED; self::assertEquals($expected, $this->docBlockGenerator->generate()); } public function testDocBlockFromReflectionLongDescription() { self::assertEquals('Long Description', $this->reflectionDocBlockGenerator->getLongDescription()); } public function testDocBlockFromReflectionShortDescription() { self::assertEquals('Short Description', $this->reflectionDocBlockGenerator->getShortDescription()); } public function testDocBlockFromReflectionTagsCount() { self::assertCount(4, $this->reflectionDocBlockGenerator->getTags()); } /** * @depends testDocBlockFromReflectionTagsCount */ public function testDocBlockFromReflectionParamTag() { $tags = $this->reflectionDocBlockGenerator->getTags(); self::assertInstanceOf(ParamTag::class, $tags[0]); } /** * @depends testDocBlockFromReflectionTagsCount */ public function testDocBlockFromReflectionAuthorTag() { $tags = $this->reflectionDocBlockGenerator->getTags(); self::assertInstanceOf(AuthorTag::class, $tags[1]); } /** * @depends testDocBlockFromReflectionTagsCount */ public function testDocBlockFromReflectionLicenseTag() { $tags = $this->reflectionDocBlockGenerator->getTags(); self::assertInstanceOf(LicenseTag::class, $tags[2]); } /** * @depends testDocBlockFromReflectionTagsCount */ public function testDocBlockFromReflectionReturnTag() { $tags = $this->reflectionDocBlockGenerator->getTags(); self::assertInstanceOf(ReturnTag::class, $tags[3]); } } php-zend-code-3.4.1/test/Generator/FileGeneratorTest.php000066400000000000000000000347271357431215700232050ustar00rootroot00000000000000setSourceContent('Foo'); self::assertEquals('Foo', $file->getSourceContent()); } public function testIndentationGetterAndSetter() { $file = new FileGenerator(); $file->setIndentation(' '); self::assertEquals(' ', $file->getIndentation()); } public function testToString() { $codeGenFile = FileGenerator::fromArray([ 'requiredFiles' => ['SampleClass.php'], 'class' => [ 'flags' => ClassGenerator::FLAG_ABSTRACT, 'name' => 'SampleClass', 'extendedClass' => 'ExtendedClassName', 'implementedInterfaces' => ['Iterator', 'Traversable'], ], ]); $expectedOutput = <<generate(); self::assertEquals($expectedOutput, $output, $output); } public function testFromReflection() { $tempFile = tempnam(sys_get_temp_dir(), 'UnitFile'); $codeGenFile = FileGenerator::fromArray([ 'class' => [ 'name' => 'SampleClass', ], ]); file_put_contents($tempFile, $codeGenFile->generate()); require_once $tempFile; $fileGenerator = FileGenerator::fromReflection(new FileReflection($tempFile)); unlink($tempFile); self::assertEquals(FileGenerator::class, get_class($fileGenerator)); self::assertCount(1, $fileGenerator->getClasses()); } public function testFromFileReflection() { $file = __DIR__ . '/TestAsset/TestSampleSingleClass.php'; require_once $file; $codeGenFileFromDisk = FileGenerator::fromReflection($fileRefl = new FileReflection($file)); $codeGenFileFromDisk->getClass()->addMethod('foobar'); $expectedOutput = <<<'EOS' */ namespace ZendTest\Code\Generator\TestAsset; /** * class docblock */ class TestSampleSingleClass { /** * Enter description here... * * @return bool */ public function someMethod() { /* test test */ } /** * Enter description here... * * @return bool */ protected function withParamsAndReturnType($mixed, array $array, ?callable $callable = null, ?int $int = 0) : bool { /* test test */ return true; } public function foobar() { } } EOS; self::assertEquals($expectedOutput, $codeGenFileFromDisk->generate()); } /** * @group test */ public function testFileLineEndingsAreAlwaysLineFeed() { $codeGenFile = FileGenerator::fromArray([ 'requiredFiles' => ['SampleClass.php'], 'class' => [ 'abstract' => true, 'name' => 'SampleClass', 'extendedClass' => 'ExtendedClassName', 'implementedInterfaces' => ['Iterator', 'Traversable'], ], ]); // explode by newline, this would leave CF in place if it were generated $lines = explode("\n", $codeGenFile->generate()); $targetLength = strlen('require_once \'SampleClass.php\';'); self::assertEquals($targetLength, strlen($lines[2])); self::assertEquals(';', $lines[2][$targetLength - 1]); } /** * @group ZF-11218 */ public function testGeneratesUseStatements() { $file = new FileGenerator(); $file->setUse('My\Baz') ->setUses([ ['use' => 'Your\Bar', 'as' => 'bar'], ]); $generated = $file->generate(); self::assertStringContainsString('use My\\Baz;', $generated); self::assertStringContainsString('use Your\\Bar as bar;', $generated); } public function testGeneratesNamespaceStatements() { $file = new FileGenerator(); $file->setNamespace('Foo\Bar'); $generated = $file->generate(); self::assertStringContainsString('namespace Foo\\Bar', $generated, $generated); } public function testSetUseDoesntGenerateMultipleIdenticalUseStatements() { $file = new FileGenerator(); $file->setUse('My\Baz') ->setUse('My\Baz'); $generated = $file->generate(); self::assertSame(strpos($generated, 'use My\\Baz'), strrpos($generated, 'use My\\Baz')); } public function testSetUsesDoesntGenerateMultipleIdenticalUseStatements() { $file = new FileGenerator(); $file->setUses([ ['use' => 'Your\Bar', 'as' => 'bar'], ['use' => 'Your\Bar', 'as' => 'bar'], ]); $generated = $file->generate(); self::assertSame(strpos($generated, 'use Your\\Bar as bar;'), strrpos($generated, 'use Your\\Bar as bar;')); } public function testSetUseAllowsMultipleAliasedUseStatements() { $file = new FileGenerator(); $file->setUses([ ['use' => 'Your\Bar', 'as' => 'bar'], ['use' => 'Your\Bar', 'as' => 'bar2'], ]); $generated = $file->generate(); self::assertStringContainsString('use Your\\Bar as bar;', $generated); self::assertStringContainsString('use Your\\Bar as bar2;', $generated); } public function testSetUsesWithArrays() { $file = new FileGenerator(); $file->setUses([ ['use' => 'Your\\Bar', 'as' => 'bar'], ['use' => 'My\\Baz', 'as' => 'FooBaz'], ]); $generated = $file->generate(); self::assertStringContainsString('use My\\Baz as FooBaz;', $generated); self::assertStringContainsString('use Your\\Bar as bar;', $generated); } public function testSetUsesWithString() { $file = new FileGenerator(); $file->setUses([ 'Your\\Bar', 'My\\Baz', ['use' => 'Another\\Baz', 'as' => 'Baz2'], ]); $generated = $file->generate(); self::assertStringContainsString('use My\\Baz;', $generated); self::assertStringContainsString('use Your\\Bar;', $generated); self::assertStringContainsString('use Another\\Baz as Baz2;', $generated); } public function testSetUsesWithGetUses() { $file = new FileGenerator(); $uses = [ 'Your\\Bar', 'My\\Baz', ['use' => 'Another\\Baz', 'as' => 'Baz2'], ]; $file->setUses($uses); $file->setUses($file->getUses()); $generated = $file->generate(); self::assertStringContainsString('use My\\Baz;', $generated); self::assertStringContainsString('use Your\\Bar;', $generated); self::assertStringContainsString('use Another\\Baz as Baz2;', $generated); } public function testCreateFromArrayWithClassInstance() { $fileGenerator = FileGenerator::fromArray([ 'filename' => 'foo.php', 'class' => new ClassGenerator('bar'), ]); $class = $fileGenerator->getClass('bar'); self::assertInstanceOf(ClassGenerator::class, $class); } public function testCreateFromArrayWithClassFromArray() { $fileGenerator = FileGenerator::fromArray([ 'filename' => 'foo.php', 'class' => [ 'name' => 'bar', ], ]); $class = $fileGenerator->getClass('bar'); self::assertInstanceOf(ClassGenerator::class, $class); } public function testGeneratingFromAReflectedFileName() { $generator = FileGenerator::fromReflectedFileName(__DIR__ . '/TestAsset/OneInterface.php'); self::assertInstanceOf(FileGenerator::class, $generator); } public function testGeneratedClassesHaveUses() { $generator = FileGenerator::fromReflectedFileName(__DIR__ . '/TestAsset/ClassWithUses.php'); $class = $generator->getClass(); $expectedUses = [TestAsset\ClassWithNamespace::class]; self::assertEquals($expectedUses, $class->getUses()); } /** * @group 4747 */ public function testIssue4747FileGenerationWithAddedMethodIsCorrectlyFormatted() { $g = new FileGenerator(); $g = $g->fromReflectedFileName(__DIR__ . '/TestAsset/ClassWithUses.php'); $g->setFilename(sys_get_temp_dir() . '/result_class.php'); $g->getClass()->addMethod('added'); $g->write(); $expected = <<<'CODE' fromReflectedFileName(__DIR__ . '/TestAsset/ClassWithUses.php'); $g->setFilename(sys_get_temp_dir() . '/result_class.php'); $g->getClass()->addMethod('added'); $g->setBody('$foo->bar();'); $g->write(); $expected = <<<'CODE' bar(); CODE; $actual = file_get_contents(sys_get_temp_dir() . '/result_class.php'); self::assertEquals($expected, $actual); } public function testSingleDeclareStatement(): void { $generator = FileGenerator::fromArray([ 'declares' => [ 'strict_types' => 1, ], 'class' => [ 'name' => 'SampleClass', ], ]); $generator->setFilename(sys_get_temp_dir() . '/result_file.php'); $generator->write(); $expected = <<assertEquals($expected, $actual); } public function testMultiDeclareStatements(): void { $generator = FileGenerator::fromArray([ 'declares' => [ 'strict_types' => 1, 'ticks' => 2, ], 'class' => [ 'name' => 'SampleClass', ], ]); $generator->setFilename(sys_get_temp_dir() . '/result_file.php'); $generator->write(); $expected = <<assertEquals($expected, $actual); } public function testDeclareUnknownDirectiveShouldRaiseException(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Declare directive must be one of: ticks, strict_types, encoding.'); FileGenerator::fromArray([ 'declares' => [ 'fubar' => 1, ], 'class' => [ 'name' => 'SampleClass', ], ]); } public function testDeclareWrongTypeShouldRaiseException(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Declare value invalid. Expected integer, got string.'); FileGenerator::fromArray([ 'declares' => [ 'strict_types' => 'wrong type', ], 'class' => [ 'name' => 'SampleClass', ], ]); } public function testDeclareDuplicatesShouldOnlyGenerateOne(): void { $generator = FileGenerator::fromArray([ 'class' => [ 'name' => 'SampleClass', ], ]); $generator->setFilename(sys_get_temp_dir() . '/result_file.php'); $generator->setDeclares([ DeclareStatement::strictTypes(1), DeclareStatement::strictTypes(2) ]); $generator->write(); $expected = <<assertEquals($expected, $actual); } public function testWrongDeclareTypeShouldRaiseException(): void { $generator = new FileGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('setDeclares is expecting an array of Zend\\Code\\DeclareStatement objects'); $generator->setDeclares([new \stdClass()]); } } php-zend-code-3.4.1/test/Generator/InterfaceGeneratorTest.php000066400000000000000000000172661357431215700242250ustar00rootroot00000000000000isAbstract()); $classGenerator->setAbstract(true); self::assertFalse($classGenerator->isAbstract()); } public function testExtendedClassAccessors() { $classGenerator = new InterfaceGenerator(); $classGenerator->setExtendedClass('ExtendedClass'); self::assertNull($classGenerator->getExtendedClass()); } public function testImplementedInterfacesAccessors() { $classGenerator = new InterfaceGenerator(); $classGenerator->setImplementedInterfaces(['Class1', 'Class2']); self::assertCount(2, $classGenerator->getImplementedInterfaces()); } public function testPropertyAccessors() { $classGenerator1 = new InterfaceGenerator(); $classGenerator2 = new InterfaceGenerator(); $classGenerator1->addProperty('prop3'); $classGenerator2->addProperties([ 'propOne', new PropertyGenerator('propTwo'), ]); self::assertCount(0, $classGenerator1->getProperties()); self::assertCount(0, $classGenerator2->getProperties()); } public function testMethodAccessors() { $classGenerator = new InterfaceGenerator(); $classGenerator->addMethods([ 'methodOne', new MethodGenerator('methodTwo'), ]); self::assertCount(2, $classGenerator->getMethods()); self::assertTrue($classGenerator->getMethod('methodOne')->isInterface()); self::assertTrue($classGenerator->getMethod('methodTwo')->isInterface()); } public function testToString() { $classGenerator = InterfaceGenerator::fromArray([ 'name' => 'SampleInterface', 'methods' => [ ['name' => 'baz'], ], ]); $expectedOutput = <<generate(); self::assertEquals($expectedOutput, $output, $output); } public function testSetextendedclassShouldIgnoreEmptyClassnameOnGenerate() { $classGeneratorClass = new InterfaceGenerator(); $classGeneratorClass ->setName('MyInterface') ->setExtendedClass(''); $expected = <<generate()); } public function testSetextendedclassShouldNotIgnoreNonEmptyClassnameOnGenerate() { $classGeneratorClass = new InterfaceGenerator(); $classGeneratorClass ->setName('MyInterface') ->setExtendedClass('MyInterface'); $expected = <<generate()); } /** * @group namespace */ public function testCodeGenerationShouldTakeIntoAccountNamespacesFromReflection() { $reflClass = new ClassReflection(FooInterface::class); $classGenerator = InterfaceGenerator::fromReflection($reflClass); self::assertEquals('ZendTest\Code\TestAsset', $classGenerator->getNamespaceName()); self::assertEquals('FooInterface', $classGenerator->getName()); $expected = <<generate(); self::assertEquals($expected, $received, $received); } /** * @group namespace */ public function testSetNameShouldDetermineIfNamespaceSegmentIsPresent() { $classGeneratorClass = new InterfaceGenerator(); $classGeneratorClass->setName('My\Namespaced\FunClass'); self::assertEquals('My\Namespaced', $classGeneratorClass->getNamespaceName()); } /** * @group namespace */ public function testPassingANamespacedClassnameShouldGenerateANamespaceDeclaration() { $classGeneratorClass = new InterfaceGenerator(); $classGeneratorClass->setName('My\Namespaced\FunClass'); $received = $classGeneratorClass->generate(); self::assertStringContainsString('namespace My\Namespaced;', $received, $received); } /** * @group namespace */ public function testPassingANamespacedClassnameShouldGenerateAClassnameWithoutItsNamespace() { $classGeneratorClass = new InterfaceGenerator(); $classGeneratorClass->setName('My\Namespaced\FunClass'); $received = $classGeneratorClass->generate(); self::assertStringContainsString('interface FunClass', $received, $received); } public function testCreateFromArrayWithDocBlockFromArray() { $classGenerator = InterfaceGenerator::fromArray([ 'name' => 'SampleClass', 'docblock' => [ 'shortdescription' => 'foo', ], ]); $docBlock = $classGenerator->getDocBlock(); self::assertInstanceOf(DocBlockGenerator::class, $docBlock); } public function testCreateFromArrayWithDocBlockInstance() { $classGenerator = InterfaceGenerator::fromArray([ 'name' => 'MyInterface', 'docblock' => new DocBlockGenerator('foo'), ]); $docBlock = $classGenerator->getDocBlock(); $output = $classGenerator->generate(); $expected = <<setName('MyInterface'); $classGenerator->addMethod('methodOne'); $expected = <<generate(); self::assertEquals($expected, $output); } public function testGenerateImplementsInterface() { $classGenerator = new InterfaceGenerator(); $classGenerator->setName('MyCollection'); $classGenerator->addMethod('isEmpty'); $classGenerator->setImplementedInterfaces(['Countable', 'IteratorAggregate']); $expected = <<generate(); self::assertEquals($expected, $output); } public function testClassNotAnInterfaceException() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Class ZendTest\Code\Generator\InterfaceGeneratorTest is not a interface'); InterfaceGenerator::fromReflection(new ClassReflection(__CLASS__)); } } php-zend-code-3.4.1/test/Generator/MethodGeneratorTest.php000066400000000000000000000330531357431215700235350ustar00rootroot00000000000000setParameters(['one']); $params = $methodGenerator->getParameters(); $param = array_shift($params); self::assertInstanceOf(ParameterGenerator::class, $param); } public function testMethodParameterMutator() { $methodGenerator = new MethodGenerator(); $methodGenerator->setParameter('foo'); $methodGenerator->setParameter(['name' => 'bar', 'type' => 'array']); $methodGenerator->setParameter(ParameterGenerator::fromArray(['name' => 'baz', 'type' => stdClass::class])); $params = $methodGenerator->getParameters(); self::assertCount(3, $params); /** @var $foo ParameterGenerator */ $foo = array_shift($params); self::assertInstanceOf(ParameterGenerator::class, $foo); self::assertEquals('foo', $foo->getName()); $bar = array_shift($params); self::assertEquals(ParameterGenerator::fromArray(['name' => 'bar', 'type' => 'array']), $bar); /** @var $baz ParameterGenerator */ $baz = array_shift($params); self::assertEquals('baz', $baz->getName()); $this->expectException(InvalidArgumentException::class); $methodGenerator->setParameter(new stdClass()); } public function testMethodBodyGetterAndSetter() { $method = new MethodGenerator(); $method->setBody('Foo'); self::assertEquals('Foo', $method->getBody()); } public function testDocBlockGetterAndSetter() { $docblockGenerator = new DocBlockGenerator(); $method = new MethodGenerator(); $method->setDocBlock($docblockGenerator); self::assertSame($docblockGenerator, $method->getDocBlock()); } public function testCopyMethodSignature() { $ref = new MethodReflection(TestAsset\TestSampleSingleClass::class, 'withParamsAndReturnType'); $methodGenerator = MethodGenerator::copyMethodSignature($ref); $target = <<<'EOS' protected function withParamsAndReturnType($mixed, array $array, ?callable $callable = null, ?int $int = 0) : bool { } EOS; self::assertEquals($target, (string) $methodGenerator); } public function testMethodFromReflection() { $ref = new MethodReflection(TestAsset\TestSampleSingleClass::class, 'someMethod'); $methodGenerator = MethodGenerator::fromReflection($ref); $target = <<setName('foo'); $methodGenerator->setParameters(['one']); $methodGenerator->setStatic(true); $expected = <<generate()); } /** * @group ZF-6444 */ public function testMethodWithFinalModifierIsEmitted() { $methodGenerator = new MethodGenerator(); $methodGenerator->setName('foo'); $methodGenerator->setParameters(['one']); $methodGenerator->setFinal(true); $expected = <<generate()); } /** * @group ZF-6444 */ public function testMethodWithFinalModifierIsNotEmittedWhenMethodIsAbstract() { $methodGenerator = new MethodGenerator(); $methodGenerator->setName('foo'); $methodGenerator->setParameters(['one']); $methodGenerator->setFinal(true); $methodGenerator->setAbstract(true); $expected = <<generate()); } /** * @group ZF-7205 */ public function testMethodCanHaveDocBlock() { $methodGeneratorProperty = new MethodGenerator( 'someFoo', [], MethodGenerator::FLAG_STATIC | MethodGenerator::FLAG_PROTECTED, null, '@var string $someVal This is some val' ); $expected = <<generate()); } /** * @group ZF-7268 */ public function testDefaultValueGenerationDoesNotIncludeTrailingSemicolon() { $method = new MethodGenerator('setOptions'); $default = new ValueGenerator(); $default->setValue([]); $param = new ParameterGenerator('options', 'array'); $param->setDefaultValue($default); $method->setParameter($param); $generated = $method->generate(); self::assertStringContainsString('array $options = [])', $generated); } public function testCreateFromArray() { $methodGenerator = MethodGenerator::fromArray([ 'name' => 'SampleMethod', 'body' => 'foo', 'docblock' => [ 'shortdescription' => 'foo', ], 'abstract' => true, 'final' => true, 'static' => true, 'visibility' => MethodGenerator::VISIBILITY_PROTECTED, 'returntype' => '\\SampleType', ]); self::assertEquals('SampleMethod', $methodGenerator->getName()); self::assertEquals('foo', $methodGenerator->getBody()); self::assertInstanceOf(DocBlockGenerator::class, $methodGenerator->getDocBlock()); self::assertTrue($methodGenerator->isAbstract()); self::assertTrue($methodGenerator->isFinal()); self::assertTrue($methodGenerator->isStatic()); self::assertEquals(MethodGenerator::VISIBILITY_PROTECTED, $methodGenerator->getVisibility()); self::assertInstanceOf(TypeGenerator::class, $methodGenerator->getReturnType()); self::assertEquals('\\SampleType', $methodGenerator->getReturnType()->generate()); } public function testCreateInterfaceMethodFromArray() { $methodGenerator = MethodGenerator::fromArray([ 'name' => 'execute', 'interface' => true, 'docblock' => [ 'shortdescription' => 'Short Description', ], ]); $expected = <<<'CODE' /** * Short Description */ public function execute(\Runnable $command); CODE; $methodGenerator->setParameter(['name' => 'command', 'type' => 'Runnable']); self::assertTrue($methodGenerator->isInterface()); self::assertEquals('execute', $methodGenerator->getName()); self::assertEquals($expected, $methodGenerator->generate()); self::assertInstanceOf(DocBlockGenerator::class, $methodGenerator->getDocBlock()); } /** * @group zendframework/zend-code#29 */ public function testSetReturnType() { $methodGenerator = new MethodGenerator(); $methodGenerator->setName('foo'); $methodGenerator->setReturnType('bar'); $expected = <<<'PHP' public function foo() : \bar { } PHP; self::assertSame($expected, $methodGenerator->generate()); } /** * @group zendframework/zend-code#29 */ public function testSetReturnTypeWithNull() { $methodGenerator = new MethodGenerator(); $methodGenerator->setName('foo'); $methodGenerator->setReturnType(null); $expected = <<<'PHP' public function foo() { } PHP; self::assertSame($expected, $methodGenerator->generate()); } /** * @group zendframework/zend-code#29 * * @dataProvider returnTypeHintClasses * * @param string $className * @param string $methodName * @param string $expectedReturnSignature */ public function testFrom($className, $methodName, $expectedReturnSignature) { $methodGenerator = MethodGenerator::fromReflection(new MethodReflection($className, $methodName)); self::assertStringMatchesFormat('%A) : ' . $expectedReturnSignature . '%A{%A', $methodGenerator->generate()); } public function returnTypeHintClasses() { $parameters = [ [ReturnTypeHintedClass::class, 'voidReturn', 'void'], [ReturnTypeHintedClass::class, 'arrayReturn', 'array'], [ReturnTypeHintedClass::class, 'callableReturn', 'callable'], [ReturnTypeHintedClass::class, 'intReturn', 'int'], [ReturnTypeHintedClass::class, 'floatReturn', 'float'], [ReturnTypeHintedClass::class, 'stringReturn', 'string'], [ReturnTypeHintedClass::class, 'boolReturn', 'bool'], [ReturnTypeHintedClass::class, 'selfReturn', '\\' . ReturnTypeHintedClass::class], [ReturnTypeHintedClass::class, 'parentReturn', '\\' . EmptyClass::class], [ReturnTypeHintedClass::class, 'classReturn', '\\' . ReturnTypeHintedClass::class], [ReturnTypeHintedClass::class, 'otherClassReturn', '\\' . InternalHintsClass::class], [NullableReturnTypeHintedClass::class, 'arrayReturn', '?array'], [NullableReturnTypeHintedClass::class, 'callableReturn', '?callable'], [NullableReturnTypeHintedClass::class, 'intReturn', '?int'], [NullableReturnTypeHintedClass::class, 'floatReturn', '?float'], [NullableReturnTypeHintedClass::class, 'stringReturn', '?string'], [NullableReturnTypeHintedClass::class, 'boolReturn', '?bool'], [NullableReturnTypeHintedClass::class, 'selfReturn', '?\\' . NullableReturnTypeHintedClass::class], [NullableReturnTypeHintedClass::class, 'parentReturn', '?\\' . EmptyClass::class], [NullableReturnTypeHintedClass::class, 'classReturn', '?\\' . NullableReturnTypeHintedClass::class], [NullableReturnTypeHintedClass::class, 'otherClassReturn', '?\\' . InternalHintsClass::class], [IterableHintsClass::class, 'iterableReturnValue', 'iterable'], [IterableHintsClass::class, 'nullableIterableReturnValue', '?iterable'], [ObjectHintsClass::class, 'objectReturnValue', 'object'], [ObjectHintsClass::class, 'nullableObjectReturnValue', '?object'], ]; return array_filter( $parameters, function (array $parameter) { return PHP_VERSION_ID >= 70200 || ( false === strpos($parameter[2], 'object') ); } ); } /** * @group zendframework/zend-code#29 */ public function testByRefReturnType() { $methodGenerator = new MethodGenerator('foo'); $methodGenerator->setReturnsReference(true); self::assertStringMatchesFormat('%Apublic function & foo()%A', $methodGenerator->generate()); $methodGenerator->setReturnsReference(false); self::assertStringMatchesFormat('%Apublic function foo()%A', $methodGenerator->generate()); } /** * @group zendframework/zend-code#29 */ public function testFromByReferenceMethodReflection() { $methodGenerator = MethodGenerator::fromReflection( new MethodReflection(ClassWithByRefReturnMethod::class, 'byRefReturn') ); self::assertStringMatchesFormat('%Apublic function & byRefReturn()%A', $methodGenerator->generate()); } } php-zend-code-3.4.1/test/Generator/ParameterGeneratorTest.php000066400000000000000000000511561357431215700242410ustar00rootroot00000000000000setType('Foo'); self::assertEquals('Foo', $parameterGenerator->getType()); } public function testNameGetterAndSetterPersistValue() { $parameterGenerator = new ParameterGenerator(); $parameterGenerator->setName('Foo'); self::assertEquals('Foo', $parameterGenerator->getName()); } public function testDefaultValueGetterAndSetterPersistValue() { $parameterGenerator = new ParameterGenerator(); $value = new ValueGenerator('Foo', ValueGenerator::TYPE_CONSTANT); $parameterGenerator->setDefaultValue($value); self::assertEquals('Foo', (string) $parameterGenerator->getDefaultValue()); } public function testPositionGetterAndSetterPersistValue() { $parameterGenerator = new ParameterGenerator(); $parameterGenerator->setPosition(2); self::assertEquals(2, $parameterGenerator->getPosition()); } public function testGenerateIsCorrect() { $parameterGenerator = new ParameterGenerator(); $parameterGenerator->setType('Foo'); $parameterGenerator->setName('bar'); $parameterGenerator->setDefaultValue(15); self::assertEquals('\\Foo $bar = 15', $parameterGenerator->generate()); $parameterGenerator->setDefaultValue('foo'); self::assertEquals('\\Foo $bar = \'foo\'', $parameterGenerator->generate()); } public function testFromReflectionGetParameterName() { $reflectionParameter = $this->getFirstReflectionParameter('name'); $codeGenParam = ParameterGenerator::fromReflection($reflectionParameter); self::assertEquals('param', $codeGenParam->getName()); } public function testFromReflectionGetParameterType() { $reflectionParameter = $this->getFirstReflectionParameter('type'); $codeGenParam = ParameterGenerator::fromReflection($reflectionParameter); self::assertEquals('stdClass', $codeGenParam->getType()); } public function testFromReflectionGetReference() { $reflectionParameter = $this->getFirstReflectionParameter('reference'); $codeGenParam = ParameterGenerator::fromReflection($reflectionParameter); self::assertTrue($codeGenParam->getPassedByReference()); } public function testFromReflectionGetDefaultValue() { $reflectionParameter = $this->getFirstReflectionParameter('defaultValue'); $codeGenParam = ParameterGenerator::fromReflection($reflectionParameter); $defaultValue = $codeGenParam->getDefaultValue(); self::assertEquals('\'foo\'', (string) $defaultValue); } /** * @group 95 */ public function testFromReflectionGetDefaultValueNotOptional() { $method = new MethodReflection(ParameterClass::class, 'defaultObjectEqualsNullAndNotOptional'); $params = $method->getParameters(); self::assertCount(2, $params); $firstParameter = ParameterGenerator::fromReflection($params[0]); self::assertInstanceOf(ValueGenerator::class, $firstParameter->getDefaultValue()); self::assertNull($firstParameter->getDefaultValue()->getSourceContent()); } public function testFromReflectionGetArrayHint() { $reflectionParameter = $this->getFirstReflectionParameter('fromArray'); $codeGenParam = ParameterGenerator::fromReflection($reflectionParameter); self::assertEquals('array', $codeGenParam->getType()); } public function testFromReflectionGetWithNativeType() { $reflectionParameter = $this->getFirstReflectionParameter('hasNativeDocTypes'); $codeGenParam = ParameterGenerator::fromReflection($reflectionParameter); self::assertNotEquals('int', $codeGenParam->getType()); self::assertEquals('', $codeGenParam->getType()); } public function testCallableTypeHint() { $parameter = ParameterGenerator::fromReflection( new ParameterReflection([TestAsset\CallableTypeHintClass::class, 'foo'], 'bar') ); self::assertEquals('callable', $parameter->getType()); } /** * @dataProvider dataFromReflectionGenerate * * @param string $methodName * @param string $expectedCode */ public function testFromReflectionGenerate($methodName, $expectedCode) { $reflectionParameter = $this->getFirstReflectionParameter($methodName); $codeGenParam = ParameterGenerator::fromReflection($reflectionParameter); self::assertEquals($expectedCode, $codeGenParam->generate()); } public function dataFromReflectionGenerate() { return [ ['name', '$param'], ['type', '\\stdClass $bar'], ['reference', '&$baz'], ['defaultValue', '$value = \'foo\''], ['defaultNull', '$value = null'], ['fromArray', 'array $array'], ['hasNativeDocTypes', '$integer'], ['defaultArray', '$array = []'], ['defaultArrayWithValues', '$array = [1, 2, 3]'], ['defaultFalse', '$val = false'], ['defaultTrue', '$val = true'], ['defaultZero', '$number = 0'], ['defaultNumber', '$number = 1234'], ['defaultFloat', '$float = 1.34'], ['defaultConstant', '$con = \'foo\''], ]; } /** * @param string $method * @return ParameterReflection */ protected function getFirstReflectionParameter($method) { $reflectionClass = new ClassReflection(TestAsset\ParameterClass::class); $method = $reflectionClass->getMethod($method); $params = $method->getParameters(); return array_shift($params); } public function testCreateFromArray() { $parameterGenerator = ParameterGenerator::fromArray([ 'name' => 'SampleParameter', 'type' => 'int', 'defaultvalue' => 'foo', 'passedbyreference' => false, 'position' => 1, 'sourcedirty' => false, 'sourcecontent' => 'foo', 'indentation' => '-', 'omitdefaultvalue' => true, ]); self::assertEquals('SampleParameter', $parameterGenerator->getName()); self::assertEquals('int', $parameterGenerator->getType()); self::assertInstanceOf(ValueGenerator::class, $parameterGenerator->getDefaultValue()); self::assertFalse($parameterGenerator->getPassedByReference()); self::assertEquals(1, $parameterGenerator->getPosition()); self::assertFalse($parameterGenerator->isSourceDirty()); self::assertEquals('foo', $parameterGenerator->getSourceContent()); self::assertEquals('-', $parameterGenerator->getIndentation()); self::assertAttributeEquals(true, 'omitDefaultValue', $parameterGenerator); } /** * @group 4988 */ public function testParameterGeneratorReturnsCorrectTypeForNonNamespaceClasses() { require_once __DIR__ . '/../TestAsset/NonNamespaceClass.php'; $reflClass = new ClassReflection('ZendTest_Code_NsTest_BarClass'); $params = $reflClass->getMethod('fooMethod')->getParameters(); $param = ParameterGenerator::fromReflection($params[0]); self::assertEquals('ZendTest_Code_NsTest_BarClass', $param->getType()); } /** * @group 5193 */ public function testTypehintsWithNamespaceInNamepsacedClassReturnTypewithBackslash() { require_once __DIR__ . '/TestAsset/NamespaceTypeHintClass.php'; $reflClass = new ClassReflection('Namespaced\TypeHint\Bar'); $params = $reflClass->getMethod('method')->getParameters(); $param = ParameterGenerator::fromReflection($params[0]); self::assertEquals('OtherNamespace\ParameterClass', $param->getType()); } /** * @group 6023 * * @coversNothing */ public function testGeneratedParametersHaveEscapedDefaultValues() { $parameter = new ParameterGenerator(); $parameter->setName('foo'); $parameter->setDefaultValue("\\'"); $parameter->setType('stdClass'); self::assertSame("\\stdClass \$foo = '\\\\\\''", $parameter->generate()); } /** * @group zendframework/zend-code#29 * * @dataProvider simpleHints * * @param string $type * @param string $expectedType */ public function testGeneratesSimpleHints($type, $expectedType) { $parameter = new ParameterGenerator(); $parameter->setName('foo'); $parameter->setType($type); self::assertSame($expectedType . ' $foo', $parameter->generate()); } /** * @return string[][] */ public function simpleHints() { return [ ['callable', 'callable'], ['Callable', 'callable'], ['CALLABLE', 'callable'], ['array', 'array'], ['Array', 'array'], ['ARRAY', 'array'], ['string', 'string'], ['String', 'string'], ['STRING', 'string'], ['bool', 'bool'], ['Bool', 'bool'], ['BOOL', 'bool'], ['int', 'int'], ['Int', 'int'], ['INT', 'int'], ['float', 'float'], ['Float', 'float'], ['FLOAT', 'float'], ]; } /** * @group zendframework/zend-code#29 * * @dataProvider validClassName * * @param string $className */ public function testTypeHintWithValidClassName($className) { $parameter = new ParameterGenerator(); $parameter->setName('foo'); $parameter->setType($className); self::assertSame('\\' . $className . ' $foo', $parameter->generate()); } /** * @return string[][] */ public function validClassName() { return [ ['stdClass'], ['foo'], ['FOO'], ['bar'], ['bar1'], ['BAR1'], ['baz\\tab'], ['baz\\tab\\taz'], ['baz\\tab\\taz1'], ['mixed'], ['Mixed'], ['MIXED'], ['resource'], ['Resource'], ['RESOURCE'], ]; } /** * @group zendframework/zend-code#29 * * @dataProvider reflectionHints * * @param string $className * @param string $methodName * @param string $parameterName * @param string|null $expectedType */ public function testTypeHintFromReflection($className, $methodName, $parameterName, $expectedType) { $parameter = ParameterGenerator::fromReflection(new ParameterReflection( [$className, $methodName], $parameterName )); if (null === $expectedType) { self::assertNull($parameter->getType()); return; } self::assertSame(ltrim($expectedType, '?\\'), $parameter->getType()); } /** * @group zendframework/zend-code#29 * * @dataProvider reflectionHints * * @param string $className * @param string $methodName * @param string $parameterName * @param string|null $expectedType */ public function testTypeHintFromReflectionGeneratedCode($className, $methodName, $parameterName, $expectedType) { $parameter = ParameterGenerator::fromReflection(new ParameterReflection( [$className, $methodName], $parameterName )); if (null === $expectedType) { self::assertStringStartsWith('$' . $parameterName, $parameter->generate()); return; } self::assertStringStartsWith($expectedType . ' $' . $parameterName, $parameter->generate()); } /** * @return string[][] */ public function reflectionHints() { $parameters = [ [InternalHintsClass::class, 'arrayParameter', 'foo', 'array'], [InternalHintsClass::class, 'callableParameter', 'foo', 'callable'], [InternalHintsClass::class, 'intParameter', 'foo', 'int'], [InternalHintsClass::class, 'floatParameter', 'foo', 'float'], [InternalHintsClass::class, 'stringParameter', 'foo', 'string'], [InternalHintsClass::class, 'boolParameter', 'foo', 'bool'], [NullableHintsClass::class, 'arrayParameter', 'foo', '?array'], [NullableHintsClass::class, 'callableParameter', 'foo', '?callable'], [NullableHintsClass::class, 'intParameter', 'foo', '?int'], [NullableHintsClass::class, 'floatParameter', 'foo', '?float'], [NullableHintsClass::class, 'stringParameter', 'foo', '?string'], [NullableHintsClass::class, 'boolParameter', 'foo', '?bool'], [NullableHintsClass::class, 'selfParameter', 'foo', '?\\' . NullableHintsClass::class], [NullableHintsClass::class, 'parentParameter', 'foo', '?\\' . EmptyClass::class], [NullableHintsClass::class, 'nullableHintsClassParameter', 'foo', '?\\' . NullableHintsClass::class], [NullNullableDefaultHintsClass::class, 'arrayParameter', 'foo', '?array'], [NullNullableDefaultHintsClass::class, 'callableParameter', 'foo', '?callable'], [NullNullableDefaultHintsClass::class, 'intParameter', 'foo', '?int'], [NullNullableDefaultHintsClass::class, 'floatParameter', 'foo', '?float'], [NullNullableDefaultHintsClass::class, 'stringParameter', 'foo', '?string'], [NullNullableDefaultHintsClass::class, 'boolParameter', 'foo', '?bool'], [ NullNullableDefaultHintsClass::class, 'selfParameter', 'foo', '?\\' . NullNullableDefaultHintsClass::class, ], [NullNullableDefaultHintsClass::class, 'parentParameter', 'foo', '?\\' . EmptyClass::class], [ NullNullableDefaultHintsClass::class, 'nullableDefaultHintsClassParameter', 'foo', '?\\' . NullNullableDefaultHintsClass::class, ], [ClassTypeHintedClass::class, 'selfParameter', 'foo', '\\' . ClassTypeHintedClass::class], [ClassTypeHintedClass::class, 'parentParameter', 'foo', '\\' . EmptyClass::class], [ClassTypeHintedClass::class, 'classParameter', 'foo', '\\' . ClassTypeHintedClass::class], [ClassTypeHintedClass::class, 'otherClassParameter', 'foo', '\\' . InternalHintsClass::class], [ClassTypeHintedClass::class, 'closureParameter', 'foo', '\\' . \Closure::class], [ClassTypeHintedClass::class, 'importedClosureParameter', 'foo', '\\' . \Closure::class], [DocBlockOnlyHintsClass::class, 'arrayParameter', 'foo', null], [DocBlockOnlyHintsClass::class, 'callableParameter', 'foo', null], [DocBlockOnlyHintsClass::class, 'intParameter', 'foo', null], [DocBlockOnlyHintsClass::class, 'floatParameter', 'foo', null], [DocBlockOnlyHintsClass::class, 'stringParameter', 'foo', null], [DocBlockOnlyHintsClass::class, 'boolParameter', 'foo', null], [DocBlockOnlyHintsClass::class, 'selfParameter', 'foo', null], [DocBlockOnlyHintsClass::class, 'classParameter', 'foo', null], [DocBlockOnlyHintsClass::class, 'otherClassParameter', 'foo', null], [IterableHintsClass::class, 'iterableParameter', 'foo', 'iterable'], [IterableHintsClass::class, 'nullableIterableParameter', 'foo', '?iterable'], [IterableHintsClass::class, 'nullDefaultIterableParameter', 'foo', '?iterable'], [ObjectHintsClass::class, 'objectParameter', 'foo', 'object'], [ObjectHintsClass::class, 'nullableObjectParameter', 'foo', '?object'], [ObjectHintsClass::class, 'nullDefaultObjectParameter', 'foo', '?object'], ]; $compatibleParameters = array_filter( $parameters, function (array $parameter) { return PHP_VERSION_ID >= 70200 || ( false === strpos($parameter[3], 'object') ); } ); // just re-organizing the keys so that the phpunit data set makes sense in errors: return array_combine( array_map( function (array $definition) { return $definition[0] . '#' . $definition[1]; }, $compatibleParameters ), $compatibleParameters ); } /** * @group zendframework/zend-code#29 * * @dataProvider variadicHints * * @param string $className * @param string $methodName * @param string $parameterName * @param string $expectedGeneratedSignature */ public function testVariadicArgumentFromReflection( $className, $methodName, $parameterName, $expectedGeneratedSignature ) { $parameter = ParameterGenerator::fromReflection(new ParameterReflection( [$className, $methodName], $parameterName )); self::assertTrue($parameter->getVariadic()); self::assertSame($expectedGeneratedSignature, $parameter->generate()); } /** * @return string[][] */ public function variadicHints() { return [ [VariadicParametersClass::class, 'firstVariadicParameter', 'foo', '... $foo'], [VariadicParametersClass::class, 'secondVariadicParameter', 'bar', '... $bar'], [ VariadicParametersClass::class, 'typeHintedVariadicParameter', 'bar', '\\' . VariadicParametersClass::class . ' ... $bar', ], [ VariadicParametersClass::class, 'byRefVariadic', 'bar', '&... $bar', ], [ VariadicParametersClass::class, 'byRefTypeHintedVariadic', 'bar', '\\' . VariadicParametersClass::class . ' &... $bar', ], ]; } /** * @group zendframework/zend-code#29 */ public function testSetGetVariadic() { $parameter = new ParameterGenerator('foo'); self::assertFalse($parameter->getVariadic(), 'Is not variadic by default'); self::assertSame('$foo', $parameter->generate()); $parameter->setVariadic(true); self::assertTrue($parameter->getVariadic()); self::assertSame('... $foo', $parameter->generate()); $parameter->setVariadic(false); self::assertFalse($parameter->getVariadic()); self::assertSame('$foo', $parameter->generate()); } /** * @group zendframework/zend-code#29 */ public function testGetInternalClassDefaultParameterValue() { $parameter = ParameterGenerator::fromReflection(new ParameterReflection([\Phar::class, 'compress'], 1)); self::assertSame('null', strtolower((string) $parameter->getDefaultValue())); } public function testOmitType() { $parameter = new ParameterGenerator('foo', 'string', 'bar'); $parameter->omitDefaultValue(); self::assertEquals('string $foo', $parameter->generate()); } } php-zend-code-3.4.1/test/Generator/PropertyGeneratorTest.php000066400000000000000000000253741357431215700241500ustar00rootroot00000000000000setType($type); $defaultValue->setValue($value); self::assertEquals($type, $defaultValue->getType()); self::assertEquals($code, $defaultValue->generate()); } /** * @dataProvider dataSetTypeSetValueGenerate * * @param string $type * @param mixed $value * @param string $code */ public function testSetBogusTypeSetValueGenerateUseAutoDetection(string $type, $value, string $code) : void { if ('constant' === $type) { self::markTestSkipped('constant can only be detected explicitly'); } $defaultValue = new PropertyValueGenerator(); $defaultValue->setType('bogus'); $defaultValue->setValue($value); self::assertEquals($code, $defaultValue->generate()); } public function testPropertyReturnsSimpleValue() : void { $codeGenProperty = new PropertyGenerator('someVal', 'some string value'); self::assertEquals(' public $someVal = \'some string value\';', $codeGenProperty->generate()); } public function testPropertyMultilineValue() : void { $targetValue = [ 5, 'one' => 1, 'two' => '2', 'null' => null, 'true' => true, "bar's" => "bar's", ]; $expectedSource = << 1, 'two' => '2', 'null' => null, 'true' => true, 'bar\'s' => 'bar\'s', ]; EOS; $property = new PropertyGenerator('myFoo', $targetValue); $targetSource = $property->generate(); $targetSource = str_replace("\r", '', $targetSource); self::assertEquals($expectedSource, $targetSource); } public function visibility() : Generator { yield 'public' => [PropertyGenerator::FLAG_PUBLIC, 'public']; yield 'protected' => [PropertyGenerator::FLAG_PROTECTED, 'protected']; yield 'private' => [PropertyGenerator::FLAG_PRIVATE, 'private']; } /** * @dataProvider visibility */ public function testPropertyCanProduceConstatWithVisibility(int $flag, string $visibility) : void { $codeGenProperty = new PropertyGenerator('FOO', 'bar', [PropertyGenerator::FLAG_CONSTANT, $flag]); self::assertSame(' ' . $visibility . ' const FOO = \'bar\';', $codeGenProperty->generate()); } public function testPropertyCanProduceContstantModifier() : void { $codeGenProperty = new PropertyGenerator('someVal', 'some string value', PropertyGenerator::FLAG_CONSTANT); self::assertEquals(' public const someVal = \'some string value\';', $codeGenProperty->generate()); } /** * @group PR-704 */ public function testPropertyCanProduceContstantModifierWithSetter() : void { $codeGenProperty = new PropertyGenerator('someVal', 'some string value'); $codeGenProperty->setConst(true); self::assertEquals(' public const someVal = \'some string value\';', $codeGenProperty->generate()); } public function testPropertyCanProduceStaticModifier() : void { $codeGenProperty = new PropertyGenerator('someVal', 'some string value', PropertyGenerator::FLAG_STATIC); self::assertEquals(' public static $someVal = \'some string value\';', $codeGenProperty->generate()); } /** * @group ZF-6444 */ public function testPropertyWillLoadFromReflection() : void { $reflectionClass = new ClassReflection(TestAsset\TestClassWithManyProperties::class); // test property 1 $reflProp = $reflectionClass->getProperty('_bazProperty'); $cgProp = PropertyGenerator::fromReflection($reflProp); self::assertEquals('_bazProperty', $cgProp->getName()); self::assertEquals([true, false, true], $cgProp->getDefaultValue()->getValue()); self::assertEquals('private', $cgProp->getVisibility()); $reflProp = $reflectionClass->getProperty('_bazStaticProperty'); // test property 2 $cgProp = PropertyGenerator::fromReflection($reflProp); self::assertEquals('_bazStaticProperty', $cgProp->getName()); self::assertEquals(TestAsset\TestClassWithManyProperties::FOO, $cgProp->getDefaultValue()->getValue()); self::assertTrue($cgProp->isStatic()); self::assertEquals('private', $cgProp->getVisibility()); } /** * @group ZF-6444 */ public function testPropertyWillEmitStaticModifier() : void { $codeGenProperty = new PropertyGenerator( 'someVal', 'some string value', PropertyGenerator::FLAG_STATIC | PropertyGenerator::FLAG_PROTECTED ); self::assertEquals(' protected static $someVal = \'some string value\';', $codeGenProperty->generate()); } /** * @group ZF-7205 */ public function testPropertyCanHaveDocBlock() : void { $codeGenProperty = new PropertyGenerator( 'someVal', 'some string value', PropertyGenerator::FLAG_STATIC | PropertyGenerator::FLAG_PROTECTED ); $codeGenProperty->setDocBlock('@var string $someVal This is some val'); $expected = <<generate()); } public function testOtherTypesThrowExceptionOnGenerate() : void { $codeGenProperty = new PropertyGenerator('someVal', new \stdClass()); $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Type "stdClass" is unknown or cannot be used as property default value'); $codeGenProperty->generate(); } public function testCreateFromArray() : void { $propertyGenerator = PropertyGenerator::fromArray([ 'name' => 'SampleProperty', 'const' => true, 'defaultvalue' => 'foo', 'docblock' => [ 'shortdescription' => 'foo', ], 'abstract' => true, 'final' => true, 'static' => true, 'visibility' => PropertyGenerator::VISIBILITY_PROTECTED, 'omitdefaultvalue' => true, ]); self::assertEquals('SampleProperty', $propertyGenerator->getName()); self::assertTrue($propertyGenerator->isConst()); self::assertInstanceOf(ValueGenerator::class, $propertyGenerator->getDefaultValue()); self::assertInstanceOf(DocBlockGenerator::class, $propertyGenerator->getDocBlock()); self::assertTrue($propertyGenerator->isAbstract()); self::assertTrue($propertyGenerator->isFinal()); self::assertTrue($propertyGenerator->isStatic()); self::assertEquals(PropertyGenerator::VISIBILITY_PROTECTED, $propertyGenerator->getVisibility()); self::assertAttributeEquals(true, 'omitDefaultValue', $propertyGenerator); } /** * @group 3491 */ public function testPropertyDocBlockWillLoadFromReflection() : void { $reflectionClass = new ClassReflection(TestAsset\TestClassWithManyProperties::class); $reflProp = $reflectionClass->getProperty('fooProperty'); $cgProp = PropertyGenerator::fromReflection($reflProp); self::assertEquals('fooProperty', $cgProp->getName()); $docBlock = $cgProp->getDocBlock(); self::assertInstanceOf(DocBlockGenerator::class, $docBlock); $tags = $docBlock->getTags(); self::assertIsArray($tags); self::assertCount(1, $tags); $tag = array_shift($tags); self::assertInstanceOf(VarTag::class, $tag); self::assertEquals('var', $tag->getName()); } /** * @dataProvider dataSetTypeSetValueGenerate * * @param string $type * @param mixed $value */ public function testSetDefaultValue(string $type, $value) : void { $property = new PropertyGenerator(); $property->setDefaultValue($value, $type); self::assertEquals($type, $property->getDefaultValue()->getType()); self::assertEquals($value, $property->getDefaultValue()->getValue()); } public function testOmitType() { $property = new PropertyGenerator('foo', null); $property->omitDefaultValue(); self::assertEquals(' public $foo;', $property->generate()); } public function testFromReflectionOmitsDefaultValueIfItIsNull() : void { $reflectionClass = new ClassReflection(TestAsset\TestClassWithManyProperties::class); $propertyReflection = $reflectionClass->getProperty('fooStaticProperty'); $generator = PropertyGenerator::fromReflection($propertyReflection); $code = $generator->generate(); $this->assertEquals(' public static $fooStaticProperty;', $code); } } php-zend-code-3.4.1/test/Generator/PropertyValueGeneratorTest.php000066400000000000000000000013521357431215700251330ustar00rootroot00000000000000generate()); } } php-zend-code-3.4.1/test/Generator/TestAsset/000077500000000000000000000000001357431215700210105ustar00rootroot00000000000000php-zend-code-3.4.1/test/Generator/TestAsset/CallableTypeHintClass.php000066400000000000000000000006671357431215700257040ustar00rootroot00000000000000 1, 1 => 2, 2 => 3]) { } const FOO = 'foo'; public function defaultConstant($con = self::FOO) { } public function defaultObjectEqualsNullAndNotOptional(\stdClass $a = null, $b) { } /** * @param int $integer */ public function hasNativeDocTypes($integer) { } } php-zend-code-3.4.1/test/Generator/TestAsset/PrototypeClass.php000066400000000000000000000010751357431215700245170ustar00rootroot00000000000000 1, 'two' => '2', [ 'bar', 'baz', "\n" ] ]; } php-zend-code-3.4.1/test/Generator/TestAsset/TestSampleSingleClass.php000066400000000000000000000011641357431215700257340ustar00rootroot00000000000000 */ namespace ZendTest\Code\Generator\TestAsset; /** * class docblock */ class TestSampleSingleClass { /** * Enter description here... * * @return bool */ public function someMethod() { /* test test */ } /** * Enter description here... * * @return bool */ protected function withParamsAndReturnType( $mixed, array $array, callable $callable = null, ?int $int = 0 ): bool { /* test test */ return true; } } php-zend-code-3.4.1/test/Generator/TestAsset/TestSampleSingleClassMultiLines.php000066400000000000000000000011541357431215700277410ustar00rootroot00000000000000setName('TestClass'); self::assertEquals('TestClass', $classGenerator->getName()); } public function testClassDocBlockAccessors() { $this->markTestIncomplete(); } public function testAbstractAccessorsReturnsFalse() { $classGenerator = new TraitGenerator(); self::assertFalse($classGenerator->isAbstract()); $classGenerator->setAbstract(true); self::assertFalse($classGenerator->isAbstract()); } public function testExtendedClassAccessors() { $classGenerator = new TraitGenerator(); $classGenerator->setExtendedClass('ExtendedClass'); self::assertNull($classGenerator->getExtendedClass()); } public function testImplementedInterfacesAccessors() { $classGenerator = new TraitGenerator(); $classGenerator->setImplementedInterfaces(['Class1', 'Class2']); self::assertCount(0, $classGenerator->getImplementedInterfaces()); } public function testPropertyAccessors() { $classGenerator = new TraitGenerator(); $classGenerator->addProperties([ 'propOne', new PropertyGenerator('propTwo'), ]); $properties = $classGenerator->getProperties(); self::assertCount(2, $properties); self::assertInstanceOf(PropertyGenerator::class, current($properties)); $property = $classGenerator->getProperty('propTwo'); self::assertInstanceOf(PropertyGenerator::class, $property); self::assertEquals('propTwo', $property->getName()); // add a new property $classGenerator->addProperty('prop3'); self::assertCount(3, $classGenerator->getProperties()); } public function testSetPropertyAlreadyExistsThrowsException() { $classGenerator = new TraitGenerator(); $classGenerator->addProperty('prop3'); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('A property by name prop3 already exists in this class'); $classGenerator->addProperty('prop3'); } public function testSetPropertyNoArrayOrPropertyThrowsException() { $classGenerator = new TraitGenerator(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Zend\Code\Generator\TraitGenerator::addProperty expects string for name'); $classGenerator->addProperty(true); } public function testMethodAccessors() { $classGenerator = new TraitGenerator(); $classGenerator->addMethods([ 'methodOne', new MethodGenerator('methodTwo'), ]); $methods = $classGenerator->getMethods(); self::assertCount(2, $methods); self::assertInstanceOf(MethodGenerator::class, current($methods)); $method = $classGenerator->getMethod('methodOne'); self::assertInstanceOf(MethodGenerator::class, $method); self::assertEquals('methodOne', $method->getName()); // add a new property $classGenerator->addMethod('methodThree'); self::assertCount(3, $classGenerator->getMethods()); } public function testSetMethodNoMethodOrArrayThrowsException() { $classGenerator = new TraitGenerator(); $this->expectException(ExceptionInterface::class); $this->expectExceptionMessage('Zend\Code\Generator\TraitGenerator::addMethod expects string for name'); $classGenerator->addMethod(true); } public function testSetMethodNameAlreadyExistsThrowsException() { $methodA = new MethodGenerator(); $methodA->setName('foo'); $methodB = new MethodGenerator(); $methodB->setName('foo'); $classGenerator = new TraitGenerator(); $classGenerator->addMethodFromGenerator($methodA); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('A method by name foo already exists in this class.'); $classGenerator->addMethodFromGenerator($methodB); } /** * @group ZF-7361 */ public function testHasMethod() { $classGenerator = new TraitGenerator(); $classGenerator->addMethod('methodOne'); self::assertTrue($classGenerator->hasMethod('methodOne')); } public function testRemoveMethod() { $classGenerator = new TraitGenerator(); $classGenerator->addMethod('methodOne'); self::assertTrue($classGenerator->hasMethod('methodOne')); $classGenerator->removeMethod('methodOne'); self::assertFalse($classGenerator->hasMethod('methodOne')); } /** * @group ZF-7361 */ public function testHasProperty() { $classGenerator = new TraitGenerator(); $classGenerator->addProperty('propertyOne'); self::assertTrue($classGenerator->hasProperty('propertyOne')); } public function testToString() { $classGenerator = TraitGenerator::fromArray([ 'name' => 'SampleClass', 'properties' => [ 'foo', ['name' => 'bar'], ], 'methods' => [ ['name' => 'baz'], ], ]); $expectedOutput = <<generate(); self::assertEquals($expectedOutput, $output, $output); } /** * @group ZF-7909 */ public function testClassFromReflectionThatImplementsInterfaces() { $reflClass = new ClassReflection(TestAsset\ClassWithInterface::class); $classGenerator = TraitGenerator::fromReflection($reflClass); $classGenerator->setSourceDirty(true); $code = $classGenerator->generate(); $expectedClassDef = 'trait ClassWithInterface'; self::assertStringContainsString($expectedClassDef, $code); } /** * @group ZF-7909 */ public function testClassFromReflectionDiscardParentImplementedInterfaces() { $reflClass = new ClassReflection(TestAsset\NewClassWithInterface::class); $classGenerator = TraitGenerator::fromReflection($reflClass); $classGenerator->setSourceDirty(true); $code = $classGenerator->generate(); $expectedClassDef = 'trait NewClassWithInterface'; self::assertStringContainsString($expectedClassDef, $code); } /** * @group 4988 */ public function testNonNamespaceClassReturnsAllMethods() { require_once __DIR__ . '/../TestAsset/NonNamespaceClass.php'; $reflClass = new ClassReflection('ZendTest_Code_NsTest_BarClass'); $classGenerator = TraitGenerator::fromReflection($reflClass); self::assertCount(1, $classGenerator->getMethods()); } /** * @group ZF-9602 */ public function testSetextendedclassShouldIgnoreEmptyClassnameOnGenerate() { $classGeneratorClass = new TraitGenerator(); $classGeneratorClass ->setName('MyClass') ->setExtendedClass(''); $expected = <<generate()); } /** * @group ZF-9602 */ public function testSetextendedclassShouldNotIgnoreNonEmptyClassnameOnGenerate() { $classGeneratorClass = new TraitGenerator(); $classGeneratorClass ->setName('MyClass') ->setExtendedClass('ParentClass'); $expected = <<generate()); } /** * @group namespace */ public function testCodeGenerationShouldTakeIntoAccountNamespacesFromReflection() { $reflClass = new ClassReflection(TestAsset\ClassWithNamespace::class); $classGenerator = TraitGenerator::fromReflection($reflClass); self::assertEquals('ZendTest\Code\Generator\TestAsset', $classGenerator->getNamespaceName()); self::assertEquals('ClassWithNamespace', $classGenerator->getName()); $expected = <<generate(); self::assertEquals($expected, $received, $received); } /** * @group namespace */ public function testSetNameShouldDetermineIfNamespaceSegmentIsPresent() { $classGeneratorClass = new TraitGenerator(); $classGeneratorClass->setName('My\Namespaced\FunClass'); self::assertEquals('My\Namespaced', $classGeneratorClass->getNamespaceName()); } /** * @group namespace */ public function testPassingANamespacedClassnameShouldGenerateANamespaceDeclaration() { $classGeneratorClass = new TraitGenerator(); $classGeneratorClass->setName('My\Namespaced\FunClass'); $received = $classGeneratorClass->generate(); self::assertStringContainsString('namespace My\Namespaced;', $received, $received); } /** * @group namespace */ public function testPassingANamespacedClassnameShouldGenerateAClassnameWithoutItsNamespace() { $classGeneratorClass = new TraitGenerator(); $classGeneratorClass->setName('My\Namespaced\FunClass'); $received = $classGeneratorClass->generate(); self::assertStringContainsString('trait FunClass', $received, $received); } /** * @group ZF2-151 */ public function testAddUses() { $classGenerator = new TraitGenerator(); $classGenerator->setName('My\Class'); $classGenerator->addUse('My\First\Use\Class'); $classGenerator->addUse('My\Second\Use\Class', 'MyAlias'); $generated = $classGenerator->generate(); self::assertStringContainsString('use My\First\Use\Class;', $generated); self::assertStringContainsString('use My\Second\Use\Class as MyAlias;', $generated); } /** * @group 4990 */ public function testAddOneUseTwiceOnlyAddsOne() { $classGenerator = new TraitGenerator(); $classGenerator->setName('My\Class'); $classGenerator->addUse('My\First\Use\Class'); $classGenerator->addUse('My\First\Use\Class'); $generated = $classGenerator->generate(); self::assertCount(1, $classGenerator->getUses()); self::assertStringContainsString('use My\First\Use\Class;', $generated); } /** * @group 4990 */ public function testAddOneUseWithAliasTwiceOnlyAddsOne() { $classGenerator = new TraitGenerator(); $classGenerator->setName('My\Class'); $classGenerator->addUse('My\First\Use\Class', 'MyAlias'); $classGenerator->addUse('My\First\Use\Class', 'MyAlias'); $generated = $classGenerator->generate(); self::assertCount(1, $classGenerator->getUses()); self::assertStringContainsString('use My\First\Use\Class as MyAlias;', $generated); } public function testCreateFromArrayWithDocBlockFromArray() { $classGenerator = TraitGenerator::fromArray([ 'name' => 'SampleClass', 'docblock' => [ 'shortdescription' => 'foo', ], ]); $docBlock = $classGenerator->getDocBlock(); self::assertInstanceOf(DocBlockGenerator::class, $docBlock); } public function testCreateFromArrayWithDocBlockInstance() { $classGenerator = TraitGenerator::fromArray([ 'name' => 'SampleClass', 'docblock' => new DocBlockGenerator('foo'), ]); $docBlock = $classGenerator->getDocBlock(); self::assertInstanceOf(DocBlockGenerator::class, $docBlock); } public function testExtendedClassProperies() { $reflClass = new ClassReflection(TestAsset\ExtendedClassWithProperties::class); $classGenerator = TraitGenerator::fromReflection($reflClass); $code = $classGenerator->generate(); self::assertStringContainsString('publicExtendedClassProperty', $code); self::assertStringContainsString('protectedExtendedClassProperty', $code); self::assertStringContainsString('privateExtendedClassProperty', $code); self::assertStringNotContainsString('publicClassProperty', $code); self::assertStringNotContainsString('protectedClassProperty', $code); self::assertStringNotContainsString('privateClassProperty', $code); } public function testHasMethodInsensitive() { $classGenerator = new TraitGenerator(); $classGenerator->addMethod('methodOne'); self::assertTrue($classGenerator->hasMethod('methodOne')); self::assertTrue($classGenerator->hasMethod('MethoDonE')); } public function testRemoveMethodInsensitive() { $classGenerator = new TraitGenerator(); $classGenerator->addMethod('methodOne'); $classGenerator->removeMethod('METHODONe'); self::assertFalse($classGenerator->hasMethod('methodOne')); } public function testGenerateClassAndAddMethod() { $classGenerator = new TraitGenerator(); $classGenerator->setName('MyClass'); $classGenerator->addMethod('methodOne'); $expected = <<generate(); self::assertEquals($expected, $output); } } php-zend-code-3.4.1/test/Generator/TypeGeneratorTest.php000066400000000000000000000163611357431215700232410ustar00rootroot00000000000000generate()); } /** * @dataProvider validType * * @param string $typeString * @param string $expectedReturnType */ public function testStringCastFromValidTypeString($typeString, $expectedReturnType) { $generator = TypeGenerator::fromTypeString($typeString); self::assertSame(ltrim($expectedReturnType, '?\\'), (string) $generator); } /** * @dataProvider validClassName * * @param string $typeString * @param string $expectedReturnType */ public function testStripsPrefixingBackslashFromClassNames($typeString, $expectedReturnType) { $generator = TypeGenerator::fromTypeString('\\' . $typeString); self::assertSame($expectedReturnType, $generator->generate()); self::assertSame(ltrim($expectedReturnType, '\\'), (string) $generator); } /** * @dataProvider invalidType * * @param string $typeString */ public function testRejectsInvalidTypeString($typeString) { $this->expectException(InvalidArgumentException::class); TypeGenerator::fromTypeString($typeString); } /** * @return string[][] */ public function validType() { $valid = [ ['foo', '\\foo'], ['foo', '\\foo'], ['foo1', '\\foo1'], ['foo\\bar', '\\foo\\bar'], ['a\\b\\c', '\\a\\b\\c'], ['foo\\bar\\baz', '\\foo\\bar\\baz'], ['foo\\bar\\baz1', '\\foo\\bar\\baz1'], ['FOO', '\\FOO'], ['FOO1', '\\FOO1'], ['void', 'void'], ['Void', 'void'], ['VOID', 'void'], ['array', 'array'], ['Array', 'array'], ['ARRAY', 'array'], ['callable', 'callable'], ['Callable', 'callable'], ['CALLABLE', 'callable'], ['string', 'string'], ['String', 'string'], ['STRING', 'string'], ['int', 'int'], ['Int', 'int'], ['INT', 'int'], ['float', 'float'], ['Float', 'float'], ['FLOAT', 'float'], ['bool', 'bool'], ['Bool', 'bool'], ['BOOL', 'bool'], ['iterable', 'iterable'], ['Iterable', 'iterable'], ['ITERABLE', 'iterable'], ['object', 'object'], ['Object', 'object'], ['OBJECT', 'object'], ['mixed', '\\mixed'], ['Mixed', '\\Mixed'], ['MIXED', '\\MIXED'], ['resource', '\\resource'], ['Resource', '\\Resource'], ['RESOURCE', '\\RESOURCE'], ['foo_bar', '\\foo_bar'], ['?foo', '?\\foo'], ['?foo', '?\\foo'], ['?foo1', '?\\foo1'], ['?foo\\bar', '?\\foo\\bar'], ['?a\\b\\c', '?\\a\\b\\c'], ['?foo\\bar\\baz', '?\\foo\\bar\\baz'], ['?foo\\bar\\baz1', '?\\foo\\bar\\baz1'], ['?FOO', '?\\FOO'], ['?FOO1', '?\\FOO1'], ['?array', '?array'], ['?Array', '?array'], ['?ARRAY', '?array'], ['?callable', '?callable'], ['?Callable', '?callable'], ['?CALLABLE', '?callable'], ['?string', '?string'], ['?String', '?string'], ['?STRING', '?string'], ['?int', '?int'], ['?Int', '?int'], ['?INT', '?int'], ['?float', '?float'], ['?Float', '?float'], ['?FLOAT', '?float'], ['?bool', '?bool'], ['?Bool', '?bool'], ['?BOOL', '?bool'], ['?iterable', '?iterable'], ['?Iterable', '?iterable'], ['?ITERABLE', '?iterable'], ['?object', '?object'], ['?Object', '?object'], ['?OBJECT', '?object'], ['?mixed', '?\\mixed'], ['?Mixed', '?\\Mixed'], ['?MIXED', '?\\MIXED'], ['?resource', '?\\resource'], ['?Resource', '?\\Resource'], ['?RESOURCE', '?\\RESOURCE'], ['?foo_bar', '?\\foo_bar'], ["\x80", "\\\x80"], ["\x80\\\x80", "\\\x80\\\x80"], ]; return array_combine( array_map('reset', $valid), $valid ); } /** * Valid class names - just the same as validType, but with only those elements prefixed by '\\' * * @return string[][] */ public function validClassName() { return array_filter( $this->validType(), function (array $pair) { return 0 === strpos($pair[1], '\\'); } ); } /** * @return string[][] */ public function invalidType() { $invalid = [ [''], ['\\'], ['\\\\'], ['\\\\foo'], ["\x7f"], ["foo\\\x7f"], ["foo\x7f\\foo"], ['1'], ['\\1'], ['\\1\\2'], ['foo\\1'], ['foo\\bar\\1'], ['1foo'], ['foo\\1foo'], ['*'], ["\0"], ['\\array'], ['\\Array'], ['\\ARRAY'], ['\\callable'], ['\\Callable'], ['\\CALLABLE'], ['\\string'], ['\\String'], ['\\STRING'], ['\\int'], ['\\Int'], ['\\INT'], ['\\float'], ['\\Float'], ['\\FLOAT'], ['\\bool'], ['\\Bool'], ['\\BOOL'], ['\\void'], ['\\Void'], ['\\VOID'], ['?void'], ['?Void'], ['?VOID'], ['\\iterable'], ['\\Iterable'], ['\\ITERABLE'], ['\\object'], ['\\Object'], ['\\OBJECT'], ]; return array_combine( array_map('reset', $invalid), $invalid ); } } php-zend-code-3.4.1/test/Generator/ValueGeneratorTest.php000066400000000000000000000341521357431215700233720ustar00rootroot00000000000000getConstants()); } public function testInvalidConstantsType() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$constants must be an instance of ArrayObject or Zend\Stdlib\ArrayObject'); $constants = $this->createMock(ArrayAccess::class); new ValueGenerator(null, ValueGenerator::TYPE_AUTO, ValueGenerator::OUTPUT_MULTIPLE_LINE, $constants); } /** * @dataProvider constantsType * * @param SplArrayObject|StdlibArrayObject $constants */ public function testAllowedPossibleConstantsType($constants) { $valueGenerator = new ValueGenerator( null, ValueGenerator::TYPE_AUTO, ValueGenerator::OUTPUT_MULTIPLE_LINE, $constants ); self::assertSame($constants, $valueGenerator->getConstants()); } public function constantsType() { return [ SplArrayObject::class => [new SplArrayObject()], StdlibArrayObject::class => [new StdlibArrayObject()], ]; } /** * @group #94 * * @dataProvider validConstantTypes * * @param PropertyValueGenerator $generator * @param string $expectedOutput */ public function testValidConstantTypes(PropertyValueGenerator $generator, $expectedOutput) { $propertyGenerator = new PropertyGenerator('FOO', $generator); $propertyGenerator->setConst(true); self::assertSame($expectedOutput, $propertyGenerator->generate()); } /** * @return array */ public function validConstantTypes() { return [ [ new PropertyValueGenerator([], PropertyValueGenerator::TYPE_ARRAY, ValueGenerator::OUTPUT_SINGLE_LINE), ' public const FOO = [];', ], [ new PropertyValueGenerator( [], PropertyValueGenerator::TYPE_ARRAY_LONG, ValueGenerator::OUTPUT_SINGLE_LINE ), ' public const FOO = array();', ], [ new PropertyValueGenerator( [], PropertyValueGenerator::TYPE_ARRAY_SHORT, ValueGenerator::OUTPUT_SINGLE_LINE ), ' public const FOO = [];', ], [new PropertyValueGenerator(true, PropertyValueGenerator::TYPE_BOOL), ' public const FOO = true;'], [new PropertyValueGenerator(true, PropertyValueGenerator::TYPE_BOOLEAN), ' public const FOO = true;'], [new PropertyValueGenerator(1, PropertyValueGenerator::TYPE_INT), ' public const FOO = 1;'], [new PropertyValueGenerator(1, PropertyValueGenerator::TYPE_INTEGER), ' public const FOO = 1;'], [new PropertyValueGenerator(0.1, PropertyValueGenerator::TYPE_DOUBLE), ' public const FOO = 0.1;'], [new PropertyValueGenerator(0.1, PropertyValueGenerator::TYPE_FLOAT), ' public const FOO = 0.1;'], [new PropertyValueGenerator('bar', PropertyValueGenerator::TYPE_STRING), " public const FOO = 'bar';"], [new PropertyValueGenerator(null, PropertyValueGenerator::TYPE_NULL), ' public const FOO = null;'], [ new PropertyValueGenerator('PHP_EOL', PropertyValueGenerator::TYPE_CONSTANT), ' public const FOO = PHP_EOL;', ], ]; } /** * @param string $longOutput * @param array $value * @return array */ protected function generateArrayData($longOutput, array $value) { $shortOutput = str_replace( ['array(', ')'], ['[', ']'], $longOutput ); return [ 'auto' => [ ValueGenerator::TYPE_AUTO, $value, $shortOutput, ], 'array' => [ ValueGenerator::TYPE_ARRAY, $value, $shortOutput, ], 'array long' => [ ValueGenerator::TYPE_ARRAY_LONG, $value, $longOutput, ], 'array short' => [ ValueGenerator::TYPE_ARRAY_SHORT, $value, $shortOutput, ], ]; } /** * Data provider for testPropertyDefaultValueCanHandleArray test * * @return array */ public function simpleArray() { $value = ['foo']; $longOutput = <<generateArrayData($longOutput, $value); } /** * Data provider for testPropertyDefaultValueCanHandleComplexArrayOfTypes test * * @return array */ public function complexArray() { $value = [ 5, 'one' => 1, 'two' => '2', 'constant1' => "__DIR__ . '/anydir1/anydir2'", [ 'baz' => true, 'foo', 'bar', [ 'baz1', 'baz2', 'constant2' => 'ArrayObject::STD_PROP_LIST', ], ], new ValueGenerator('PHP_EOL', 'constant'), ]; $longOutput = << 1, 'two' => '2', 'constant1' => __DIR__ . '/anydir1/anydir2', array( 'baz' => true, 'foo', 'bar', array( 'baz1', 'baz2', 'constant2' => ArrayObject::STD_PROP_LIST, ), ), PHP_EOL, ) EOS; return $this->generateArrayData($longOutput, $value); } /** * Data provider for testPropertyDefaultValueCanHandleComplexArrayWCustomIndentOfTypes test */ public function complexArrayWCustomIndent(): array { $value = [ '5bcf08a0a5d20' => [ '5bcf08a0a5d65' => [ '5bcf08a0a5d9f' => [ '5bcf08a0a5dd8' => [ '5bcf08a0a5e11' => [ '5bcf08a0a5e4f' => '5bcf08a0a5e8c', '5bcf08a0a5eca' => '5bcf08a0a5f05', '5bcf08a0a5f43' => '5bcf08a0a5f7f', '5bcf08a0a5fbd' => '5bcf08a0a5ff8', ], ], '5bcf08a0a603a' => [], '5bcf08a0a6062' => '5bcf08a0a609f', '5bcf08a0a60dc' => [ '5bcf08a0a611b' => '5bcf08a0a6158', '5bcf08a0a6197' => [ '5bcf08a0a61d7' => '5bcf08a0a6212', '5bcf08a0a6250' => '5bcf08a0a628c', '5bcf08a0a62cb' => '5bcf08a0a6306', ], '5bcf08a0a6345' => [ '5bcf08a0a637e' => '5bcf08a0a63b4', '5bcf08a0a63ee' => '5bcf08a0a642a', ], '5bcf08a0a6449' => '5bcf08a0a6485', ], ], ], '5bcf08a0a64c8' => '5bcf08a0a6540', '5bcf08a0a657f' => '5bcf08a0a65bf', ], ]; $longOutput = << array( '5bcf08a0a5d65' => array( '5bcf08a0a5d9f' => array( '5bcf08a0a5dd8' => array( '5bcf08a0a5e11' => array( '5bcf08a0a5e4f' => '5bcf08a0a5e8c', '5bcf08a0a5eca' => '5bcf08a0a5f05', '5bcf08a0a5f43' => '5bcf08a0a5f7f', '5bcf08a0a5fbd' => '5bcf08a0a5ff8', ), ), '5bcf08a0a603a' => array( ), '5bcf08a0a6062' => '5bcf08a0a609f', '5bcf08a0a60dc' => array( '5bcf08a0a611b' => '5bcf08a0a6158', '5bcf08a0a6197' => array( '5bcf08a0a61d7' => '5bcf08a0a6212', '5bcf08a0a6250' => '5bcf08a0a628c', '5bcf08a0a62cb' => '5bcf08a0a6306', ), '5bcf08a0a6345' => array( '5bcf08a0a637e' => '5bcf08a0a63b4', '5bcf08a0a63ee' => '5bcf08a0a642a', ), '5bcf08a0a6449' => '5bcf08a0a6485', ), ), ), '5bcf08a0a64c8' => '5bcf08a0a6540', '5bcf08a0a657f' => '5bcf08a0a65bf', ), ) EOS; return $this->generateArrayData($longOutput, $value); } /** * Data provider for testPropertyDefaultValueCanHandleArrayWithUnsortedKeys test * * @return array */ public function unsortedKeysArray() { $value = [ 1 => 'a', 0 => 'b', 'c', 7 => 'd', 3 => 'e', ]; $longOutput = << 'a', 0 => 'b', 'c', 7 => 'd', 3 => 'e', ) EOS; return $this->generateArrayData($longOutput, $value); } /** * @dataProvider unsortedKeysArray * * @param string $type * @param array $value * @param string $expected */ public function testPropertyDefaultValueCanHandleArrayWithUnsortedKeys($type, array $value, $expected) { $valueGenerator = new ValueGenerator(); $valueGenerator->setType($type); $valueGenerator->setValue($value); self::assertEquals($expected, $valueGenerator->generate()); } public function testPropertyDefaultValueConstructor() { $valueGenerator = new ValueGenerator(); self::assertInstanceOf(ValueGenerator::class, $valueGenerator); } public function testPropertyDefaultValueIsSettable() { $valueGenerator = new ValueGenerator(); $valueGenerator->setValue('foo'); self::assertEquals('foo', $valueGenerator->getValue()); } public function testPropertyDefaultValueCanHandleStrings() { $valueGenerator = new ValueGenerator(); $valueGenerator->setValue('foo'); self::assertEquals("'foo'", $valueGenerator->generate()); } /** * @dataProvider simpleArray * * @param string $type * @param array $value * @param string $expected */ public function testPropertyDefaultValueCanHandleArray($type, array $value, $expected) { $valueGenerator = new ValueGenerator(); $valueGenerator->setType($type); $valueGenerator->setValue($value); self::assertEquals($expected, $valueGenerator->generate()); } public function testPropertyDefaultValueCanHandleUnquotedString() { $valueGenerator = new ValueGenerator(); $valueGenerator->setValue('PHP_EOL'); $valueGenerator->setType('constant'); self::assertEquals('PHP_EOL', $valueGenerator->generate()); $valueGenerator = new ValueGenerator(); $valueGenerator->setValue(5); self::assertEquals('5', $valueGenerator->generate()); $valueGenerator = new ValueGenerator(); $valueGenerator->setValue(5.25); self::assertEquals('5.25', $valueGenerator->generate()); } /** * @dataProvider complexArray * * @param string $type * @param array $value * @param string $expected */ public function testPropertyDefaultValueCanHandleComplexArrayOfTypes($type, array $value, $expected) { $valueGenerator = new ValueGenerator(); $valueGenerator->initEnvironmentConstants(); $valueGenerator->setType($type); $valueGenerator->setValue($value); self::assertEquals($expected, $valueGenerator->generate()); } /** * @dataProvider complexArrayWCustomIndent */ public function testPropertyDefaultValueCanHandleComplexArrayWCustomIndentOfTypes( string $type, array $value, string $expected ) : void { $valueGenerator = new ValueGenerator(); $valueGenerator->setType($type); $valueGenerator->setValue($value); $valueGenerator->setIndentation("\t"); self::assertEquals($expected, $valueGenerator->generate()); } /** * @group 6023 * * @dataProvider getEscapedParameters * * @param string $input * @param string $expectedEscapedValue */ public function testEscaping($input, $expectedEscapedValue) { self::assertSame($expectedEscapedValue, ValueGenerator::escape($input, false)); } /** * Data provider for escaping tests * * @return string[][] */ public function getEscapedParameters() { return [ ['\\', '\\\\'], ["'", "\\'"], ["\\'", "\\\\\\'"], ]; } public function invalidValue() : Generator { yield 'object' => [new DateTime(), DateTime::class]; yield 'resource' => [fopen('php://input', 'r'), 'resource']; } /** * @dataProvider invalidValue * * @param mixed $value */ public function testExceptionInvalidValue($value, string $type) : void { $valueGenerator = new ValueGenerator($value); $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Type "'.$type.'" is unknown or cannot be used'); $valueGenerator->generate(); } } php-zend-code-3.4.1/test/Generic/000077500000000000000000000000001357431215700165175ustar00rootroot00000000000000php-zend-code-3.4.1/test/Generic/Prototype/000077500000000000000000000000001357431215700205245ustar00rootroot00000000000000php-zend-code-3.4.1/test/Generic/Prototype/PrototypeClassFactoryTest.php000066400000000000000000000040641357431215700264240ustar00rootroot00000000000000prototypeFactory = new PrototypeClassFactory(); } protected function tearDown() : void { $this->prototypeFactory = null; } public function testAddAndGetPrototype() { $proto = new PrototypeClass(); $this->prototypeFactory->addPrototype($proto); self::assertNotSame($proto, $this->prototypeFactory->getClonedPrototype($proto->getName())); self::assertEquals($proto, $this->prototypeFactory->getClonedPrototype($proto->getName())); } public function testFallBackToGeneric() { $proto = new PrototypeGenericClass(); $this->prototypeFactory->setGenericPrototype($proto); self::assertNotSame($proto, $this->prototypeFactory->getClonedPrototype('notexist')); self::assertEquals($proto, $this->prototypeFactory->getClonedPrototype('notexist')); } public function testSetNameOnGenericIsCalledOnce() { $mockProto = $this->getMockBuilder(PrototypeGenericClass::class) ->setMethods(['setName']) ->getMock(); $mockProto->expects($this->once())->method('setName')->willReturn('notexist'); $this->prototypeFactory->setGenericPrototype($mockProto); $this->prototypeFactory->getClonedPrototype('notexist'); } } php-zend-code-3.4.1/test/NameInformationTest.php000066400000000000000000000044171357431215700216100ustar00rootroot00000000000000getNamespace()); $nr = new NameInformation(); $nr->setNamespace('Bar\Baz'); self::assertEquals('Bar\Baz', $nr->getNamespace()); } public function testNamespaceResolverPersistsUseRules() { $nr = new NameInformation('Foo\Bar', ['Aaa\Bbb\Ccc' => 'C']); self::assertEquals(['Aaa\Bbb\Ccc' => 'C'], $nr->getUses()); $nr = new NameInformation(); $nr->setUses(['Aaa\Bbb\Ccc']); self::assertEquals(['Aaa\Bbb\Ccc' => 'Ccc'], $nr->getUses()); $nr->setUses(['ArrayObject']); self::assertEquals(['ArrayObject' => 'ArrayObject'], $nr->getUses()); $nr->setUses(['ArrayObject' => 'AO']); self::assertEquals(['ArrayObject' => 'AO'], $nr->getUses()); $nr->setUses(['\Aaa\Bbb\Ccc' => 'Ccc']); self::assertEquals(['Aaa\Bbb\Ccc' => 'Ccc'], $nr->getUses()); } public function testNamespaceResolverCorrectlyResolvesNames() { $nr = new NameInformation(); $nr->setNamespace('Zend\MagicComponent'); $nr->setUses([ 'ArrayObject', 'Zend\OtherMagicComponent\Foo', 'Zend\SuperMagic' => 'SM', ]); // test against namespace self::assertEquals('Zend\MagicComponent\Bar', $nr->resolveName('Bar')); // test against uses self::assertEquals('ArrayObject', $nr->resolveName('ArrayObject')); self::assertEquals('ArrayObject', $nr->resolveName('\ArrayObject')); self::assertEquals('Zend\OtherMagicComponent\Foo', $nr->resolveName('Foo')); self::assertEquals('Zend\SuperMagic', $nr->resolveName('SM')); self::assertEquals('Zend\SuperMagic\Bar', $nr->resolveName('SM\Bar')); } } php-zend-code-3.4.1/test/Reflection/000077500000000000000000000000001357431215700172355ustar00rootroot00000000000000php-zend-code-3.4.1/test/Reflection/ClassReflectionTest.php000066400000000000000000000146251357431215700236760ustar00rootroot00000000000000getMethod('getProp1'); self::assertEquals(MethodReflection::class, get_class($methodByName)); $methodsAll = $reflectionClass->getMethods(); self::assertCount(3, $methodsAll); $firstMethod = array_shift($methodsAll); self::assertEquals('getProp1', $firstMethod->getName()); } public function testPropertyReturns() { $reflectionClass = new ClassReflection(TestAsset\TestSampleClass2::class); $propertyByName = $reflectionClass->getProperty('_prop1'); self::assertInstanceOf(PropertyReflection::class, $propertyByName); $propertiesAll = $reflectionClass->getProperties(); self::assertCount(2, $propertiesAll); $firstProperty = array_shift($propertiesAll); self::assertEquals('_prop1', $firstProperty->getName()); } public function testParentReturn() { $reflectionClass = new ClassReflection(TestAsset\TestSampleClass::class); $parent = $reflectionClass->getParentClass(); self::assertEquals(ClassReflection::class, get_class($parent)); self::assertEquals('ArrayObject', $parent->getName()); } public function testInterfaceReturn() { $reflectionClass = new ClassReflection(TestAsset\TestSampleClass4::class); $interfaces = $reflectionClass->getInterfaces(); self::assertCount(1, $interfaces); $interface = array_shift($interfaces); self::assertEquals(TestAsset\TestSampleClassInterface::class, $interface->getName()); } public function testGetContentsReturnsContents() { $reflectionClass = new ClassReflection(TestAsset\TestSampleClass2::class); $target = <<_prop1; } public function getProp2(\$param1, TestSampleClass \$param2) { return \$this->_prop2; } public function getIterator() { return []; } } EOS; $contents = $reflectionClass->getContents(); self::assertEquals(trim($target), trim($contents)); } public function testGetContentsReturnsContentsWithImplementsOnSeparateLine() { $reflectionClass = new ClassReflection(TestAsset\TestSampleClass9::class); $target = <<_prop1; } public function getProp2(\$param1, TestSampleClass \$param2) { return \$this->_prop2; } public function getIterator() { return []; } } EOS; $contents = $reflectionClass->getContents(); self::assertEquals(trim($target), trim($contents)); } public function testStartLine() { $reflectionClass = new ClassReflection(TestAsset\TestSampleClass5::class); self::assertEquals(18, $reflectionClass->getStartLine()); self::assertEquals(5, $reflectionClass->getStartLine(true)); } public function testGetDeclaringFileReturnsFilename() { $reflectionClass = new ClassReflection(TestAsset\TestSampleClass2::class); self::assertStringContainsString('TestSampleClass2.php', $reflectionClass->getDeclaringFile()->getFileName()); } public function testGetAnnotationsWithNoNameInformations() { $reflectionClass = new InjectableClassReflection( // TestSampleClass5 has the annotations required to get to the // right point in the getAnnotations method. TestAsset\TestSampleClass5::class ); $annotationManager = new AnnotationManager(); $fileScanner = $this->getMockBuilder(FileScanner::class) ->disableOriginalConstructor() ->getMock(); $reflectionClass->setFileScanner($fileScanner); $fileScanner->method('getClassNameInformation') ->willReturn(false); self::assertFalse($reflectionClass->getAnnotations($annotationManager)); } public function testGetContentsReturnsEmptyContentsOnEvaldCode() { $className = uniqid('ClassReflectionTestGenerated'); eval('namespace ' . __NAMESPACE__ . '; class ' . $className . '{}'); $reflectionClass = new ClassReflection(__NAMESPACE__ . '\\' . $className); self::assertSame('', $reflectionClass->getContents()); } public function testGetContentsReturnsEmptyContentsOnInternalCode() { $reflectionClass = new ClassReflection('ReflectionClass'); self::assertSame('', $reflectionClass->getContents()); } public function testGetTraits() { // PHP documentations mentions that getTraits() return NULL in case of error. I don't know how to cause such // error so I test just normal behaviour. $reflectionClass = new ClassReflection(TestAsset\TestTraitClass4::class); $traitsArray = $reflectionClass->getTraits(); self::assertIsArray($traitsArray); self::assertCount(1, $traitsArray); self::assertInstanceOf(ClassReflection::class, $traitsArray[0]); $reflectionClass = new ClassReflection(TestAsset\TestSampleClass::class); $traitsArray = $reflectionClass->getTraits(); self::assertIsArray($traitsArray); self::assertCount(0, $traitsArray); } } php-zend-code-3.4.1/test/Reflection/DocBlock/000077500000000000000000000000001357431215700207155ustar00rootroot00000000000000php-zend-code-3.4.1/test/Reflection/DocBlock/Tag/000077500000000000000000000000001357431215700214305ustar00rootroot00000000000000php-zend-code-3.4.1/test/Reflection/DocBlock/Tag/AuthorTagTest.php000066400000000000000000000024201357431215700246750ustar00rootroot00000000000000tag = new AuthorTag(); } public function testParseName() { $this->tag->initialize('Firstname Lastname'); self::assertEquals('author', $this->tag->getName()); self::assertEquals('Firstname Lastname', $this->tag->getAuthorName()); } public function testParseNameAndEmail() { $this->tag->initialize('Firstname Lastname '); self::assertEquals('author', $this->tag->getName()); self::assertEquals('Firstname Lastname', $this->tag->getAuthorName()); self::assertEquals('test@domain.fr', $this->tag->getAuthorEmail()); } } php-zend-code-3.4.1/test/Reflection/DocBlock/Tag/GenericTagTest.php000066400000000000000000000014761357431215700250210ustar00rootroot00000000000000initialize('baz zab'); self::assertEquals('baz', $tag->returnValue(0)); self::assertEquals('zab', $tag->returnValue(1)); } } php-zend-code-3.4.1/test/Reflection/DocBlock/Tag/LicenseTagTest.php000066400000000000000000000024041357431215700250170ustar00rootroot00000000000000tag = new LicenseTag(); } public function testParseUrl() { $this->tag->initialize('http://www.example.com'); self::assertEquals('license', $this->tag->getName()); self::assertEquals('http://www.example.com', $this->tag->getUrl()); } public function testParseUrlAndLicenseName() { $this->tag->initialize('http://www.example.com Foo'); self::assertEquals('license', $this->tag->getName()); self::assertEquals('http://www.example.com', $this->tag->getUrl()); self::assertEquals('Foo', $this->tag->getLicenseName()); } } php-zend-code-3.4.1/test/Reflection/DocBlock/Tag/MethodTagTest.php000066400000000000000000000052401357431215700246560ustar00rootroot00000000000000initialize('test()'); self::assertEquals('method', $tag->getName()); self::assertEquals('test()', $tag->getMethodName()); self::assertFalse($tag->isStatic()); self::assertNull($tag->getReturnType()); self::assertNull($tag->getDescription()); } public function testParseNameAndType() { $tag = new MethodTag(); $tag->initialize('string|null test()'); self::assertEquals('method', $tag->getName()); self::assertEquals('test()', $tag->getMethodName()); self::assertFalse($tag->isStatic()); self::assertEquals('string', $tag->getReturnType()); self::assertEquals(['string', 'null'], $tag->getTypes()); self::assertNull($tag->getDescription()); } public function testParseNameAndStatic() { $tag = new MethodTag(); $tag->initialize('static test()'); self::assertEquals('method', $tag->getName()); self::assertEquals('test()', $tag->getMethodName()); self::assertTrue($tag->isStatic()); self::assertNull($tag->getReturnType()); self::assertNull($tag->getDescription()); } public function testParseNameAndStaticAndDescription() { $tag = new MethodTag(); $tag->initialize('static test() I\'m test method'); self::assertEquals('method', $tag->getName()); self::assertEquals('test()', $tag->getMethodName()); self::assertTrue($tag->isStatic()); self::assertNull($tag->getReturnType()); self::assertEquals('I\'m test method', $tag->getDescription()); } public function testParseNameAndTypeAndStaticAndDescription() { $tag = new MethodTag(); $tag->initialize('static string test() I\'m test method'); self::assertEquals('method', $tag->getName()); self::assertEquals('test()', $tag->getMethodName()); self::assertTrue($tag->isStatic()); self::assertEquals('string', $tag->getReturnType()); self::assertEquals('I\'m test method', $tag->getDescription()); } } php-zend-code-3.4.1/test/Reflection/DocBlock/Tag/PropertyTagTest.php000066400000000000000000000036371357431215700252720ustar00rootroot00000000000000initialize('$test'); self::assertEquals('property', $tag->getName()); self::assertEquals('$test', $tag->getPropertyName()); self::assertNull($tag->getType()); self::assertNull($tag->getDescription()); } public function testParseTypeAndName() { $tag = new PropertyTag(); $tag->initialize('string|null $test'); self::assertEquals('$test', $tag->getPropertyName()); self::assertNull($tag->getDescription()); self::assertEquals('string', $tag->getType()); self::assertEquals(['string', 'null'], $tag->getTypes()); } public function testParseNameAndDescription() { $tag = new PropertyTag(); $tag->initialize('$test I\'m test property'); self::assertEquals('$test', $tag->getPropertyName()); self::assertNull($tag->getType()); self::assertEquals('I\'m test property', $tag->getDescription()); } public function testParseTypeAndNameAndDescription() { $tag = new PropertyTag(); $tag->initialize('string $test I\'m test property'); self::assertEquals('$test', $tag->getPropertyName()); self::assertEquals('string', $tag->getType()); self::assertEquals('I\'m test property', $tag->getDescription()); } } php-zend-code-3.4.1/test/Reflection/DocBlock/Tag/ThrowsTagTest.php000066400000000000000000000036621357431215700247320ustar00rootroot00000000000000initialize('\\Logic_2_Exception'); self::assertEquals(['\\Logic_2_Exception'], $tag->getTypes()); } public function testSingleTypeWithDescription() { $tag = new ThrowsTag(); $tag->initialize('LogicException The Exception'); self::assertEquals(['LogicException'], $tag->getTypes()); self::assertEquals('The Exception', $tag->getDescription()); } public function testSingleTypeWithoutDescription() { $tag = new ThrowsTag(); $tag->initialize('LogicException'); self::assertEquals(['LogicException'], $tag->getTypes()); self::assertNull($tag->getDescription()); } public function testMultipleTypesWithoutDescription() { $tag = new ThrowsTag(); $tag->initialize('LogicException|RuntimeException'); self::assertEquals(['LogicException', 'RuntimeException'], $tag->getTypes()); self::assertNull($tag->getDescription()); } public function testMultipleTypesWithDescription() { $tag = new ThrowsTag(); $tag->initialize('LogicException|RuntimeException The Exception'); self::assertEquals(['LogicException', 'RuntimeException'], $tag->getTypes()); self::assertEquals('The Exception', $tag->getDescription()); } } php-zend-code-3.4.1/test/Reflection/DocBlock/Tag/VarTagTest.php000066400000000000000000000053661357431215700241770ustar00rootroot00000000000000initialize($line); $this->assertSame($expectedTypes, $tag->getTypes()); $this->assertSame($expectedVariableName, $tag->getVariableName()); $this->assertSame($expectedDescription, $tag->getDescription()); } public function varTagProvider(): array { return [ 'only type' => [ 'string', ['string'], null, null, ], 'only multiple types' => [ 'string|int', ['string', 'int'], null, null, ], 'type and name' => [ 'string $test', ['string'], '$test', null, ], 'multiple types and name' => [ 'string|int $test', ['string', 'int'], '$test', null, ], 'only name' => [ '$test', [], '$test', null, ], 'name and description' => [ '$test Foo Bar', [], '$test', 'Foo Bar', ], 'type and description' => [ 'string Foo bar', ['string'], null, 'Foo bar', ], 'multiple types and description' => [ 'string|int Foo bar', ['string', 'int'], null, 'Foo bar', ], 'type, name and description' => [ 'string $test Foo bar', ['string'], '$test', 'Foo bar', ], 'multiple types, name and description' => [ 'string|int $test Foo bar', ['string', 'int'], '$test', 'Foo bar', ], ]; } } php-zend-code-3.4.1/test/Reflection/DocBlockReflectionTest.php000066400000000000000000000201371357431215700243040ustar00rootroot00000000000000getDocBlock()->getShortDescription() ); } public function testDocBlockLongDescription() { $classReflection = new ClassReflection(TestAsset\TestSampleClass5::class); $expectedOutput = 'This is a long description for the docblock of this class, it should be longer ' . 'than 3 lines. It indeed is longer than 3 lines now.'; self::assertEquals($expectedOutput, $classReflection->getDocBlock()->getLongDescription()); } public function testDocBlockTags() { $classReflection = new ClassReflection(TestAsset\TestSampleClass5::class); self::assertCount(3, $classReflection->getDocBlock()->getTags()); self::assertCount(1, $classReflection->getDocBlock()->getTags('author')); self::assertCount(1, $classReflection->getDocBlock()->getTags('property')); self::assertCount(1, $classReflection->getDocBlock()->getTags('method')); $methodTag = $classReflection->getDocBlock()->getTag('method'); self::assertInstanceOf(MethodTag::class, $methodTag); $propertyTag = $classReflection->getDocBlock()->getTag('property'); self::assertInstanceOf(PropertyTag::class, $propertyTag); self::assertFalse($classReflection->getDocBlock()->getTag('version')); self::assertTrue($classReflection->getMethod('doSomething')->getDocBlock()->hasTag('return')); $returnTag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('return'); self::assertInstanceOf(TagInterface::class, $returnTag); self::assertEquals('mixed', $returnTag->getType()); } public function testShortDocBlocks() { $classReflection = new ClassReflection(TestAsset\TestSampleClass13::class); self::assertCount(0, $classReflection->getDocBlock()->getTags()); self::assertSame( 'Short Method Description', $classReflection->getMethod('doSomething')->getDocBlock()->getShortDescription() ); self::assertSame('Short Class Description', $classReflection->getDocBlock()->getShortDescription()); $returnTag = $classReflection->getMethod('returnSomething')->getDocBlock()->getTag('return'); self::assertInstanceOf(TagInterface::class, $returnTag); self::assertEquals('Something', $returnTag->getType()); self::assertEquals('This describes something', $returnTag->getDescription()); } public function testTabbedDocBlockTags() { $classReflection = new ClassReflection(TestAsset\TestSampleClass10::class); self::assertCount(3, $classReflection->getDocBlock()->getTags()); self::assertCount(1, $classReflection->getDocBlock()->getTags('author')); self::assertCount(1, $classReflection->getDocBlock()->getTags('property')); self::assertCount(1, $classReflection->getDocBlock()->getTags('method')); $methodTag = $classReflection->getDocBlock()->getTag('method'); self::assertInstanceOf(MethodTag::class, $methodTag); $propertyTag = $classReflection->getDocBlock()->getTag('property'); self::assertInstanceOf(PropertyTag::class, $propertyTag); self::assertFalse($classReflection->getDocBlock()->getTag('version')); self::assertTrue($classReflection->getMethod('doSomething')->getDocBlock()->hasTag('return')); $returnTag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('return'); self::assertInstanceOf(TagInterface::class, $returnTag); self::assertEquals('mixed', $returnTag->getType()); } public function testDocBlockLines() { $classReflection = new ClassReflection(TestAsset\TestSampleClass5::class); $classDocBlock = $classReflection->getDocBlock(); self::assertEquals(5, $classDocBlock->getStartLine()); self::assertEquals(17, $classDocBlock->getEndLine()); } public function testDocBlockContents() { $classReflection = new ClassReflection(TestAsset\TestSampleClass5::class); $classDocBlock = $classReflection->getDocBlock(); $expectedContents = << @method test() @property \$test EOS; self::assertEquals($expectedContents, $classDocBlock->getContents()); } public function testToString() { $classReflection = new ClassReflection(TestAsset\TestSampleClass5::class); $classDocBlock = $classReflection->getDocBlock(); $expectedString = 'DocBlock [ /* DocBlock */ ] {' . "\n" . "\n" . ' - Tags [3] {' . "\n" . ' DocBlock Tag [ * @author ]' . "\n" . ' DocBlock Tag [ * @method ]' . "\n" . ' DocBlock Tag [ * @property ]' . "\n" . ' }' . "\n" . '}' . "\n"; self::assertEquals($expectedString, (string) $classDocBlock); } public function testFunctionDocBlockTags() { $docblock = ' /** * Method ShortDescription * * @param int $one Description for one * @param int[] Description for two * @param string|null $three Description for three * which spans multiple lines * @return int[]|null Description * @throws Exception */ '; $docblockReflection = new DocBlockReflection($docblock); $paramTags = $docblockReflection->getTags('param'); self::assertCount(5, $docblockReflection->getTags()); self::assertCount(3, $paramTags); self::assertCount(1, $docblockReflection->getTags('return')); self::assertCount(1, $docblockReflection->getTags('throws')); $returnTag = $docblockReflection->getTag('return'); self::assertInstanceOf(ReturnTag::class, $returnTag); self::assertEquals('int[]', $returnTag->getType()); self::assertEquals(['int[]', 'null'], $returnTag->getTypes()); self::assertEquals('Description', $returnTag->getDescription()); $throwsTag = $docblockReflection->getTag('throws'); self::assertInstanceOf(ThrowsTag::class, $throwsTag); self::assertEquals('Exception', $throwsTag->getType()); $paramTag = $paramTags[0]; self::assertInstanceOf(ParamTag::class, $paramTag); self::assertEquals('int', $paramTag->getType()); $paramTag = $paramTags[1]; self::assertInstanceOf(ParamTag::class, $paramTag); self::assertEquals('int[]', $paramTag->getType()); $paramTag = $paramTags[2]; self::assertInstanceOf(ParamTag::class, $paramTag); self::assertEquals('string', $paramTag->getType()); self::assertEquals(['string', 'null'], $paramTag->getTypes()); } } php-zend-code-3.4.1/test/Reflection/FileReflectionTest.php000066400000000000000000000164701357431215700235100ustar00rootroot00000000000000expectException(InvalidArgumentException::class); $this->expectExceptionMessage('found'); new FileReflection($nonExistentFile); } public function testFileConstructorFromAReflectedFilenameInIncludePathWithoutIncludeFlagEnabled() { $this->expectException(RuntimeException::class); $this->expectExceptionMessage('must be required'); $oldIncludePath = set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/TestAsset/'); try { new FileReflection('an_empty_file.php', false); set_include_path($oldIncludePath); $this->fail('Should throw exception'); } catch (Exception $e) { set_include_path($oldIncludePath); throw $e; } } public function testFileConstructorFromAReflectedFilenameIncluded() { include_once __DIR__ . '/TestAsset/an_empty_file.php'; $oldIncludePath = set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/TestAsset/'); try { $file = new FileReflection('an_empty_file.php', false); self::assertSame('an_empty_file.php', $file->getFileName()); } finally { set_include_path($oldIncludePath); } } public function testFileConstructorFromAReflectedFilenameInIncludePath() { self::assertNotContains(realpath(__DIR__ . '/TestAsset/a_second_empty_file.php'), get_included_files()); $oldIncludePath = set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/TestAsset/'); try { new FileReflection('a_second_empty_file.php', true); set_include_path($oldIncludePath); } catch (Exception $e) { set_include_path($oldIncludePath); throw $e; } } public function testFileGetClassReturnsClassReflectionObject() { $fileToReflect = __DIR__ . '/TestAsset/TestSampleClass.php'; include_once $fileToReflect; $reflectionFile = new FileReflection($fileToReflect); self::assertEquals(get_class($reflectionFile), FileReflection::class); self::assertCount(1, $reflectionFile->getClasses()); } public function testFileGetClassReturnsFirstClassWithNoOptions() { $fileToReflect = __DIR__ . '/TestAsset/TestSampleClass.php'; include_once $fileToReflect; $reflectionFile = new FileReflection($fileToReflect); self::assertEquals(TestAsset\TestSampleClass::class, $reflectionFile->getClass()->getName()); } public function testFileGetClassThrowsExceptionOnNonExistentClassName() { $fileToReflect = __DIR__ . '/TestAsset/TestSampleClass.php'; include_once $fileToReflect; $reflectionFile = new FileReflection($fileToReflect); $nonExistentClass = 'Some_Non_Existent_Class'; $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Class by name Some_Non_Existent_Class not found'); $reflectionFile->getClass($nonExistentClass); } public function testFileReflectorRequiredFunctionsDoNothing() { self::assertNull(FileReflection::export()); $reflectionFile = new FileReflection(__FILE__); self::assertEquals('', $reflectionFile->__toString()); } public function testFileGetFilenameReturnsCorrectFilename() { $reflectionFile = new FileReflection(__FILE__); self::assertEquals('FileReflectionTest.php', $reflectionFile->getFileName()); } public function testFileGetLineNumbersWorks() { $this->markTestIncomplete('Line numbering not implemented yet'); $fileToReflect = __DIR__ . '/TestAsset/TestSampleClass.php'; include_once $fileToReflect; $reflectionFile = new FileReflection($fileToReflect); self::assertEquals(9, $reflectionFile->getStartLine()); self::assertEquals(24, $reflectionFile->getEndLine()); } public function testFileGetDocBlockReturnsFileDocBlock() { $fileToReflect = __DIR__ . '/TestAsset/TestSampleClass7.php'; include_once $fileToReflect; $reflectionFile = new FileReflection($fileToReflect); $reflectionDocBlock = $reflectionFile->getDocBlock(); self::assertInstanceOf(DocBlockReflection::class, $reflectionDocBlock); $authorTag = $reflectionDocBlock->getTag('author'); self::assertEquals('Jeremiah Small', $authorTag->getAuthorName()); self::assertEquals('jsmall@soliantconsulting.com', $authorTag->getAuthorEmail()); } public function testFileGetFunctionsReturnsFunctions() { $this->markTestIncomplete('Function scanning not implemented yet'); $fileToRequire = __DIR__ . '/TestAsset/FileOfFunctions.php'; include_once $fileToRequire; $reflectionFile = new FileReflection($fileToRequire); $funcs = $reflectionFile->getFunctions(); self::assertInstanceOf(FunctionReflection::class, current($funcs)); } public function testFileCanReflectFileWithInterface() { $fileToReflect = __DIR__ . '/TestAsset/TestSampleInterface.php'; include_once $fileToReflect; $reflectionFile = new FileReflection($fileToReflect); $class = $reflectionFile->getClass(); self::assertEquals(TestAsset\TestSampleInterface::class, $class->getName()); self::assertTrue($class->isInterface()); } public function testFileCanReflectFileWithUses() { $fileToReflect = __DIR__ . '/TestAsset/TestSampleClass8.php'; include_once $fileToReflect; $reflectionFile = new FileReflection($fileToReflect); $expected = [ ['use' => 'Zend\Config', 'as' => 'ZendConfig'], ['use' => 'FooBar\Foo\Bar', 'as' => null], ['use' => 'One\Two\Three\Four\Five', 'as' => 'ottff'], ]; self::assertSame($expected, $reflectionFile->getUses()); } /** * @group 70 * @group 43 */ public function testFileReflectionShouldNotRaiseNoticesWhenReflectingClosures() { require_once __DIR__ . '/TestAsset/issue-70.php'; $r = new FileReflection(__DIR__ . '/TestAsset/issue-70.php'); self::assertStringContainsString('spl_autoload_register', $r->getContents()); self::assertStringContainsString('function ()', $r->getContents()); } } php-zend-code-3.4.1/test/Reflection/FunctionReflectionTest.php000066400000000000000000000267361357431215700244240ustar00rootroot00000000000000getParameters(); self::assertCount(4, $parameters); self::assertInstanceOf(ParameterReflection::class, array_shift($parameters)); } public function testFunctionDocBlockReturn() { require_once __DIR__ . '/TestAsset/functions.php'; $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function3'); self::assertInstanceOf(DocBlockReflection::class, $function->getDocBlock()); } public function testGetPrototypeMethod() { require_once __DIR__ . '/TestAsset/functions.php'; $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function2'); $prototype = [ 'namespace' => 'ZendTest\Code\Reflection\TestAsset', 'name' => 'function2', 'return' => 'string', 'arguments' => [ 'one' => [ 'type' => 'string', 'required' => true, 'by_ref' => false, 'default' => null, ], 'two' => [ 'type' => 'string', 'required' => false, 'by_ref' => false, 'default' => 'two', ], ], ]; self::assertEquals($prototype, $function->getPrototype()); self::assertEquals( 'string function2(string $one, string $two = \'two\')', $function->getPrototype(FunctionReflection::PROTOTYPE_AS_STRING) ); } public function testInternalFunctionBodyReturn() { $function = new FunctionReflection('array_splice'); $this->expectException(InvalidArgumentException::class); $function->getBody(); } public function testFunctionBodyReturn() { require_once __DIR__ . '/TestAsset/functions.php'; $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function1'); $body = $function->getBody(); self::assertEquals("return 'function1';", trim($body)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function4'); $body = $function->getBody(); self::assertEquals("return 'function4';", trim($body)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function5'); $body = $function->getBody(); self::assertEquals("return 'function5';", trim($body)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function6'); $body = $function->getBody(); self::assertEquals("\$closure = function() { return 'bar'; };\n return 'function6';", trim($body)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function7'); $body = $function->getBody(); self::assertEquals("return 'function7';", trim($body)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function8'); $body = $function->getBody(); self::assertEquals("return 'function8';", trim($body)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function9'); $body = $function->getBody(); self::assertEquals("return 'function9';", trim($body)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function10'); $body = $function->getBody(); self::assertEquals("\$closure = function() { return 'function10'; }; return \$closure();", trim($body)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function11'); $body = $function->getBody(); self::assertEquals("return 'function11';", trim($body)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function12'); $body = $function->getBody() ?: ''; self::assertEquals('', trim($body)); } public function testFunctionClosureBodyReturn() { require __DIR__ . '/TestAsset/closures.php'; $function = new FunctionReflection($function1); $body = $function->getBody(); self::assertEquals("return 'function1';", trim($body)); $function = new FunctionReflection($function2); $body = $function->getBody(); self::assertEquals("return 'function2';", trim($body)); $function = new FunctionReflection($function3); $body = $function->getBody(); self::assertEquals("return 'function3';", trim($body)); $function = new FunctionReflection($function4); $body = $function->getBody(); self::assertEquals("\$closure = function() { return 'bar'; };\n return 'function4';", trim($body)); $function5 = $list1['closure']; $function = new FunctionReflection($function5); $body = $function->getBody(); self::assertEquals("return 'function5';", trim($body)); $function6 = $list2[0]; $function = new FunctionReflection($function6); $body = $function->getBody(); self::assertEquals("return 'function6';", trim($body)); $function7 = $list3[0]; $function = new FunctionReflection($function7); $body = $function->getBody(); self::assertEquals("return \$c = function() { return 'function7'; }; return \$c();", trim($body)); $function = new FunctionReflection($function8); $body = $function->getBody(); self::assertEquals("return 'function 8';", trim($body)); $function = new FunctionReflection($function9); $body = $function->getBody() ?: ''; self::assertEquals('', trim($body)); $function = new FunctionReflection($function10); $body = $function->getBody(); self::assertEquals("return 'function10';", trim($body)); } public function testInternalFunctionContentsReturn() { $function = new FunctionReflection('array_splice'); self::assertEmpty($function->getContents()); } public function testFunctionContentsReturnWithoutDocBlock() { require_once __DIR__ . '/TestAsset/functions.php'; $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function1'); $content = $function->getContents(false); self::assertEquals("function function1()\n{\n return 'function1';\n}", trim($content)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function4'); $content = $function->getContents(false); self::assertEquals("function function4(\$arg) {\n return 'function4';\n}", trim($content)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function5'); $content = $function->getContents(false); self::assertEquals("function function5() { return 'function5'; }", trim($content)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function6'); $content = $function->getContents(false); self::assertEquals( "function function6()\n{\n \$closure = function() { return 'bar'; };\n return 'function6';\n}", trim($content) ); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function7'); $content = $function->getContents(false); self::assertEquals("function function7() { return 'function7'; }", trim($content)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function8'); $content = $function->getContents(false); self::assertEquals("function function8() { return 'function8'; }", trim($content)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function9'); $content = $function->getContents(false); self::assertEquals("function function9() { return 'function9'; }", trim($content)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function10'); $content = $function->getContents(false); self::assertEquals( "function function10() { \$closure = function() { return 'function10'; }; return \$closure(); }", trim($content) ); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function11'); $content = $function->getContents(false); self::assertEquals("function function11() { return 'function11'; }", trim($content)); $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function12'); $content = $function->getContents(false); self::assertEquals('function function12() {}', trim($content)); } /** * @group fail */ public function testFunctionClosureContentsReturnWithoutDocBlock() { require __DIR__ . '/TestAsset/closures.php'; $function = new FunctionReflection($function2); $content = $function->getContents(false); self::assertEquals("function() { return 'function2'; }", trim($content)); $function = new FunctionReflection($function9); $content = $function->getContents(false); self::assertEquals('function() {}', trim($content)); $function = new FunctionReflection($function10); $content = $function->getContents(false); self::assertEquals("function() { return 'function10'; }", trim($content)); } public function testFunctionContentsReturnWithDocBlock() { require_once __DIR__ . '/TestAsset/functions.php'; $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function3'); $content = $function->getContents(); self::assertEquals( "/**\n * Enter description here...\n *\n * @param string \$one\n * @param int \$two" . "\n * @return true\n */\nfunction function3(\$one, \$two = 2)\n{\n return true;\n}", trim($content) ); } public function testFunctionClosureContentsReturnWithDocBlock() { require __DIR__ . '/TestAsset/closures.php'; $function = new FunctionReflection($function9); $content = $function->getContents(); self::assertEquals("/**\n * closure doc block\n */\nfunction() {}", trim($content)); } public function testGetContentsReturnsEmptyContentsOnEvaldCode() { $functionName = uniqid('generatedFunction'); eval('namespace ' . __NAMESPACE__ . '; function ' . $functionName . '(){}'); $reflectionFunction = new FunctionReflection(__NAMESPACE__ . '\\' . $functionName); self::assertSame('', $reflectionFunction->getContents()); } public function testGetContentsReturnsEmptyContentsOnInternalCode() { $reflectionFunction = new FunctionReflection('max'); self::assertSame('', $reflectionFunction->getContents()); } } php-zend-code-3.4.1/test/Reflection/MethodReflectionTest.php000066400000000000000000000343421357431215700240470ustar00rootroot00000000000000getDeclaringClass()); } public function testParemeterReturn() { $method = new MethodReflection(TestAsset\TestSampleClass2::class, 'getProp2'); $parameters = $method->getParameters(); self::assertCount(2, $parameters); self::assertInstanceOf(ParameterReflection::class, array_shift($parameters)); } public function testStartLine() { $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass5::class, 'doSomething'); self::assertEquals(37, $reflectionMethod->getStartLine()); self::assertEquals(21, $reflectionMethod->getStartLine(true)); } public function testInternalFunctionBodyReturn() { $reflectionMethod = new MethodReflection('DOMDocument', 'validate'); self::assertEmpty($reflectionMethod->getBody()); } public function testGetBodyReturnsCorrectBody() { $body = ' //we need a multi-line method body. $assigned = 1; $alsoAssigined = 2; return \'mixedValue\';'; $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass6::class, 'doSomething'); self::assertEquals($body, $reflectionMethod->getBody()); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'doSomething'); $body = $reflectionMethod->getBody(); self::assertEquals(trim($body), "return 'doSomething';"); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'doSomethingElse'); $body = $reflectionMethod->getBody(); self::assertEquals(trim($body), "return 'doSomethingElse';"); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'doSomethingAgain'); $body = $reflectionMethod->getBody(); self::assertEquals( trim($body), "\$closure = function(\$foo) { return \$foo; };\n\n return 'doSomethingAgain';" ); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'doStaticSomething'); $body = $reflectionMethod->getBody(); self::assertEquals(trim($body), "return 'doStaticSomething';"); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'inline1'); $body = $reflectionMethod->getBody(); self::assertEquals(trim($body), "return 'inline1';"); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'inline2'); $body = $reflectionMethod->getBody(); self::assertEquals(trim($body), "return 'inline2';"); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'inline3'); $body = $reflectionMethod->getBody(); self::assertEquals(trim($body), "return 'inline3';"); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'emptyFunction'); $body = $reflectionMethod->getBody(); self::assertEquals(trim($body), ''); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'visibility'); $body = $reflectionMethod->getBody(); self::assertEquals(trim($body), "return 'visibility';"); } public function testInternalMethodContentsReturn() { $reflectionMethod = new MethodReflection('DOMDocument', 'validate'); self::assertEquals('', $reflectionMethod->getContents()); } /** * @group 6275 */ public function testMethodContentsReturnWithoutDocBlock() { $contents = <<getContents(false)); $contents = ' public function doSomethingElse($one, $two = 2, $three = \'three\')' . ' { return \'doSomethingElse\'; }'; $reflectionMethod = new MethodReflection( TestAsset\TestSampleClass11::class, 'doSomethingElse' ); self::assertEquals($contents, $reflectionMethod->getContents(false)); $contents = <<<'CONTENTS' public function doSomethingAgain() { $closure = function($foo) { return $foo; }; return 'doSomethingAgain'; } CONTENTS; $reflectionMethod = new MethodReflection( TestAsset\TestSampleClass11::class, 'doSomethingAgain' ); self::assertEquals($contents, $reflectionMethod->getContents(false)); $contents = ' public function inline1() { return \'inline1\'; }'; $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'inline1'); self::assertEquals($contents, $reflectionMethod->getContents(false)); $contents = ' public function inline2() { return \'inline2\'; }'; $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'inline2'); self::assertEquals($contents, $reflectionMethod->getContents(false)); $contents = ' public function inline3() { return \'inline3\'; }'; $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'inline3'); self::assertEquals($contents, $reflectionMethod->getContents(false)); $contents = <<<'CONTENTS' public function visibility() { return 'visibility'; } CONTENTS; $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'visibility'); self::assertEquals($contents, $reflectionMethod->getContents(false)); } public function testFunctionContentsReturnWithDocBlock() { $contents = <<<'CONTENTS' /** * Doc block doSomething * @return string */ public function doSomething() { return 'doSomething'; } CONTENTS; $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'doSomething'); self::assertEquals($contents, $reflectionMethod->getContents(true)); self::assertEquals($contents, $reflectionMethod->getContents()); $contents = <<<'CONTENTS' /** * Awesome doc block */ public function emptyFunction() {} CONTENTS; $reflectionMethod = new MethodReflection( TestAsset\TestSampleClass11::class, 'emptyFunction' ); self::assertEquals($contents, $reflectionMethod->getContents(true)); } public function testGetPrototypeMethod() { $reflectionMethod = new MethodReflection( TestAsset\TestSampleClass10::class, 'doSomethingElse' ); $prototype = [ 'namespace' => 'ZendTest\Code\Reflection\TestAsset', 'class' => 'TestSampleClass10', 'name' => 'doSomethingElse', 'visibility' => 'public', 'return' => 'int', 'arguments' => [ 'one' => [ 'type' => 'int', 'required' => true, 'by_ref' => false, 'default' => null, ], 'two' => [ 'type' => 'int', 'required' => false, 'by_ref' => false, 'default' => 2, ], 'three' => [ 'type' => 'string', 'required' => false, 'by_ref' => false, 'default' => 'three', ], ], ]; self::assertEquals($prototype, $reflectionMethod->getPrototype()); self::assertEquals( 'public int doSomethingElse(int $one, int $two = 2, string $three = \'three\')', $reflectionMethod->getPrototype(MethodReflection::PROTOTYPE_AS_STRING) ); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass2::class, 'getProp2'); $prototype = [ 'namespace' => 'ZendTest\Code\Reflection\TestAsset', 'class' => 'TestSampleClass2', 'name' => 'getProp2', 'visibility' => 'public', 'return' => 'mixed', 'arguments' => [ 'param1' => [ 'type' => '', 'required' => true, 'by_ref' => false, 'default' => null, ], 'param2' => [ 'type' => TestAsset\TestSampleClass::class, 'required' => true, 'by_ref' => false, 'default' => null, ], ], ]; self::assertEquals($prototype, $reflectionMethod->getPrototype()); self::assertEquals( 'public mixed getProp2($param1, ZendTest\Code\Reflection\TestAsset\TestSampleClass $param2)', $reflectionMethod->getPrototype(MethodReflection::PROTOTYPE_AS_STRING) ); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass12::class, 'doSomething'); $prototype = [ 'namespace' => 'ZendTest\Code\Reflection\TestAsset', 'class' => 'TestSampleClass12', 'name' => 'doSomething', 'visibility' => 'protected', 'return' => 'string', 'arguments' => [ 'one' => [ 'type' => 'int', 'required' => true, 'by_ref' => true, 'default' => null, ], 'two' => [ 'type' => 'int', 'required' => true, 'by_ref' => false, 'default' => null, ], ], ]; self::assertEquals($prototype, $reflectionMethod->getPrototype()); self::assertEquals( 'protected string doSomething(int &$one, int $two)', $reflectionMethod->getPrototype(MethodReflection::PROTOTYPE_AS_STRING) ); } public function testGetAnnotationsWithNoNameInformations() { $reflectionMethod = new InjectableMethodReflection( // TestSampleClass5 has the annotations required to get to the // right point in the getAnnotations method. TestAsset\TestSampleClass5::class, 'doSomething' ); $annotationManager = new AnnotationManager(); $fileScanner = $this->getMockBuilder(CachingFileScanner::class) ->disableOriginalConstructor() ->getMock(); $reflectionMethod->setFileScanner($fileScanner); $fileScanner->method('getClassNameInformation') ->willReturn(false); self::assertFalse($reflectionMethod->getAnnotations($annotationManager)); } /** * @group 5062 */ public function testGetContentsWithCoreClass() { $reflectionMethod = new MethodReflection('DateTime', 'format'); self::assertEquals('', $reflectionMethod->getContents(false)); } public function testGetContentsReturnsEmptyContentsOnEvaldCode() { $className = uniqid('MethodReflectionTestGenerated'); eval('namespace ' . __NAMESPACE__ . '; class ' . $className . '{function foo(){}}'); $reflectionMethod = new MethodReflection(__NAMESPACE__ . '\\' . $className, 'foo'); self::assertSame('', $reflectionMethod->getContents()); self::assertSame('', $reflectionMethod->getBody()); } public function testGetContentsReturnsEmptyContentsOnInternalCode() { $reflectionMethod = new MethodReflection('ReflectionClass', 'getName'); self::assertSame('', $reflectionMethod->getContents()); } /** * @group 6275 */ public function testCodeGetContentsDoesNotThrowExceptionOnDocBlock() { $contents = <<<'CONTENTS' function getCacheKey() { $args = func_get_args(); $cacheKey = ''; foreach($args as $arg) { if (is_array($arg)) { foreach ($arg as $argElement) { $cacheKey = hash('sha256', $cacheKey.$argElement); } } else { $cacheKey = hash('sha256', $cacheKey.$arg); } //blah } return $cacheKey; } CONTENTS; $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, 'getCacheKey'); self::assertEquals($contents, $reflectionMethod->getContents(false)); } /** * @group 6275 */ public function testCodeGetBodyReturnsEmptyWithCommentedFunction() { $this->expectException('ReflectionException'); $reflectionMethod = new MethodReflection(TestAsset\TestSampleClass11::class, '__prototype'); $reflectionMethod->getBody(); } /** * @group 6620 */ public function testCanParseClassBodyWhenUsingTrait() { require_once __DIR__ . '/TestAsset/TestTraitClass1.php'; require_once __DIR__ . '/TestAsset/TestTraitClass2.php'; // $method = new \Zend\Code\Reflection\ClassReflection('\FooClass'); // $traits = current($method->getTraits()); $method = new MethodReflection('FooClass', 'getDummy'); self::assertEquals(trim($method->getBody()), 'return $this->dummy;'); } } php-zend-code-3.4.1/test/Reflection/ParameterReflectionTest.php000066400000000000000000000152341357431215700245460ustar00rootroot00000000000000getDeclaringClass()); } public function testClassReturnNoClassGivenReturnsNull() { $parameter = new Reflection\ParameterReflection( [TestAsset\TestSampleClass2::class, 'getProp2'], 'param1' ); self::assertNull($parameter->getClass()); } public function testClassReturn() { $parameter = new Reflection\ParameterReflection( [TestAsset\TestSampleClass2::class, 'getProp2'], 'param2' ); self::assertInstanceOf(ClassReflection::class, $parameter->getClass()); } /** * @dataProvider paramType * * @param string $param * @param string $type */ public function testTypeReturn($param, $type) { $parameter = new Reflection\ParameterReflection( [TestAsset\TestSampleClass5::class, 'doSomething'], $param ); self::assertEquals($type, $parameter->detectType()); } public function testCallableTypeHint() { $parameter = new Reflection\ParameterReflection( [TestAsset\CallableTypeHintClass::class, 'foo'], 'bar' ); self::assertEquals('callable', $parameter->detectType()); } public function paramType() { return [ ['one','int'], ['two','int'], ['three','string'], ['array','array'], ['class',TestAsset\TestSampleClass::class], ]; } /** * @group zendframework/zend-code#29 * * @dataProvider reflectionHints * * @param string $className * @param string $methodName * @param string $parameterName * @param string $expectedType */ public function testGetType($className, $methodName, $parameterName, $expectedType) { $reflection = new Reflection\ParameterReflection( [$className, $methodName], $parameterName ); $type = $reflection->getType(); self::assertInstanceOf(\ReflectionType::class, $type); self::assertSame($expectedType, $type->getName()); } /** * @group zendframework/zend-code#29 * * @dataProvider reflectionHints * * @param string $className * @param string $methodName * @param string $parameterName * @param string $expectedType */ public function testDetectType($className, $methodName, $parameterName, $expectedType) { $reflection = new Reflection\ParameterReflection( [$className, $methodName], $parameterName ); // following is just due to an incompatibility between this test method and `testGetType` if ('self' === $expectedType) { $expectedType = $className; } self::assertSame($expectedType, $reflection->detectType()); } /** * @return string[][] */ public function reflectionHints() { return [ [InternalHintsClass::class, 'arrayParameter', 'foo', 'array'], [InternalHintsClass::class, 'callableParameter', 'foo', 'callable'], [InternalHintsClass::class, 'intParameter', 'foo', 'int'], [InternalHintsClass::class, 'floatParameter', 'foo', 'float'], [InternalHintsClass::class, 'stringParameter', 'foo', 'string'], [InternalHintsClass::class, 'boolParameter', 'foo', 'bool'], [ClassTypeHintedClass::class, 'selfParameter', 'foo', 'self'], [ClassTypeHintedClass::class, 'classParameter', 'foo', ClassTypeHintedClass::class], [ClassTypeHintedClass::class, 'otherClassParameter', 'foo', InternalHintsClass::class], [ClassTypeHintedClass::class, 'closureParameter', 'foo', \Closure::class], [ClassTypeHintedClass::class, 'importedClosureParameter', 'foo', \Closure::class], ]; } /** * @group zendframework/zend-code#29 * * @dataProvider docBlockHints * * @param string $className * @param string $methodName * @param string $parameterName */ public function testGetTypeWithDocBlockOnlyTypes($className, $methodName, $parameterName) { $reflection = new Reflection\ParameterReflection( [$className, $methodName], $parameterName ); self::assertNull($reflection->getType()); } /** * @group zendframework/zend-code#29 * * @dataProvider docBlockHints * * @param string $className * @param string $methodName * @param string $parameterName * @param string $expectedType */ public function testDetectTypeWithDocBlockOnlyTypes($className, $methodName, $parameterName, $expectedType) { $reflection = new Reflection\ParameterReflection( [$className, $methodName], $parameterName ); self::assertSame($expectedType, $reflection->detectType()); } /** * @return string[][] */ public function docBlockHints() { return [ [DocBlockOnlyHintsClass::class, 'arrayParameter', 'foo', 'array'], [DocBlockOnlyHintsClass::class, 'callableParameter', 'foo', 'callable'], [DocBlockOnlyHintsClass::class, 'intParameter', 'foo', 'int'], [DocBlockOnlyHintsClass::class, 'floatParameter', 'foo', 'float'], [DocBlockOnlyHintsClass::class, 'stringParameter', 'foo', 'string'], [DocBlockOnlyHintsClass::class, 'boolParameter', 'foo', 'bool'], [DocBlockOnlyHintsClass::class, 'selfParameter', 'foo', 'self'], [DocBlockOnlyHintsClass::class, 'classParameter', 'foo', 'DocBlockOnlyHintsClass'], [DocBlockOnlyHintsClass::class, 'otherClassParameter', 'foo', 'InternalHintsClass'], ]; } } php-zend-code-3.4.1/test/Reflection/PropertyReflectionTest.php000066400000000000000000000056751357431215700244620ustar00rootroot00000000000000getDeclaringClass()); self::assertEquals(TestAsset\TestSampleClass2::class, $property->getDeclaringClass()->getName()); } public function testAnnotationScanningIsPossible() { $manager = new AnnotationManager(); $parser = new GenericAnnotationParser(); $parser->registerAnnotation(new TestAsset\SampleAnnotation()); $manager->attach($parser); $property = new PropertyReflection(TestAsset\TestSampleClass2::class, '_prop2'); $annotations = $property->getAnnotations($manager); self::assertInstanceOf(AnnotationCollection::class, $annotations); self::assertTrue($annotations->hasAnnotation(TestAsset\SampleAnnotation::class)); $found = false; foreach ($annotations as $key => $annotation) { if (! $annotation instanceof TestAsset\SampleAnnotation) { continue; } self::assertEquals(get_class($annotation) . ': {"foo":"bar"}', $annotation->content); $found = true; break; } self::assertTrue($found); } public function testGetAnnotationsWithNoNameInformations() { $reflectionProperty = new InjectablePropertyReflection( // TestSampleClass5 has the annotations required to get to the // right point in the getAnnotations method. TestAsset\TestSampleClass2::class, '_prop2' ); $annotationManager = new AnnotationManager(); $fileScanner = $this->getMockBuilder(CachingFileScanner::class) ->disableOriginalConstructor() ->getMock(); $reflectionProperty->setFileScanner($fileScanner); $fileScanner->method('getClassNameInformation') ->willReturn(false); self::assertFalse($reflectionProperty->getAnnotations($annotationManager)); } } php-zend-code-3.4.1/test/Reflection/ReflectionDocBlockTagTest.php000066400000000000000000000146031357431215700247410ustar00rootroot00000000000000getDocBlock()->getTag('author'); self::assertEquals('Ralph Schindler', $authorTag->getAuthorName()); self::assertEquals('ralph.schindler@zend.com', $authorTag->getAuthorEmail()); } public function testTagShouldAllowJustTagNameInDocBlockTagLine() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass6::class); $tag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('emptyTag'); self::assertEquals('emptyTag', $tag->getName(), 'Factory First Match Failed'); } public function testTagShouldAllowMultipleWhitespacesBeforeDescription() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass6::class); $tag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('descriptionTag'); self::assertNotEquals( ' A tag with just a description', $tag->getContent(), 'Final Match Failed' ); self::assertEquals( 'A tag with just a description', $tag->getContent(), 'Final Match Failed' ); } public function testToString() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass6::class); $tag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('descriptionTag'); $expectedString = 'DocBlock Tag [ * @descriptionTag ]' . "\n"; self::assertEquals($expectedString, (string) $tag); } public function testTypeParam() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass5::class); $paramTag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('param'); self::assertEquals('int', $paramTag->getType()); } public function testVariableName() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass5::class); $paramTag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('param'); self::assertEquals('$one', $paramTag->getVariableName()); } public function testAllowsMultipleSpacesInDocBlockTagLine() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass6::class); $paramTag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('param'); self::assertEquals('int', $paramTag->getType(), 'Second Match Failed'); self::assertEquals('$var', $paramTag->getVariableName(), 'Third Match Failed'); self::assertEquals( 'Description of $var', $paramTag->getDescription(), 'Final Match Failed' ); } /** * @group ZF-8307 */ public function testNamespaceInParam() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass7::class); $paramTag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('param'); self::assertEquals('Zend\Foo\Bar', $paramTag->getType()); self::assertEquals('$var', $paramTag->getVariableName()); self::assertEquals('desc', $paramTag->getDescription()); } public function testType() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass5::class); $paramTag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('return'); self::assertEquals('mixed', $paramTag->getType()); } public function testAllowsMultipleSpacesInDocBlockTagLine2() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass6::class); $paramTag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('return'); self::assertEquals('string', $paramTag->getType(), 'Second Match Failed'); self::assertEquals( 'Description of return value', $paramTag->getDescription(), 'Final Match Failed' ); } /** * @group ZF-8307 */ public function testReturnClassWithNamespace() { $classReflection = new Reflection\ClassReflection(TestAsset\TestSampleClass7::class); $paramTag = $classReflection->getMethod('doSomething')->getDocBlock()->getTag('return'); self::assertEquals('Zend\Code\Reflection\DocBlock', $paramTag->getType()); } /** * @dataProvider propertyVarDocProvider */ public function testPropertyVarDoc( string $property, array $expectedTypes, ?string $expectedName, ?string $expectedDescription ) { $classReflection = new Reflection\ClassReflection( TestAsset\TestSampleClass14::class ); /** @var VarTag $varTag */ $varTag = $classReflection ->getProperty($property) ->getDocBlock() ->getTag('var'); self::assertSame($expectedTypes, $varTag->getTypes()); self::assertSame($expectedName, $varTag->getVariableName()); self::assertSame($expectedDescription, $varTag->getDescription()); } public function propertyVarDocProvider(): array { return [ 'only type' => ['onlyType', ['string'], null, null], 'type and description' => [ 'typeDescription', ['string'], null, 'Foo bar', ], 'type and name' => ['typeName', ['string'], '$typeName', null], 'type, name and description' => [ 'typeNameDescription', ['string'], '$typeNameDescription', 'Foo bar', ], ]; } } php-zend-code-3.4.1/test/Reflection/TestAsset/000077500000000000000000000000001357431215700211545ustar00rootroot00000000000000php-zend-code-3.4.1/test/Reflection/TestAsset/CallableTypeHintClass.php000066400000000000000000000006701357431215700260420ustar00rootroot00000000000000fileScanner = $fileScanner; } protected function createFileScanner($filename) { return $this->fileScanner; } } php-zend-code-3.4.1/test/Reflection/TestAsset/InjectableMethodReflection.php000066400000000000000000000006111357431215700270770ustar00rootroot00000000000000fileScanner = $fileScanner; } protected function createFileScanner($filename) { return $this->fileScanner; } } php-zend-code-3.4.1/test/Reflection/TestAsset/InjectablePropertyReflection.php000066400000000000000000000006171357431215700275110ustar00rootroot00000000000000fileScanner = $fileScanner; } protected function createFileScanner($filename) { return $this->fileScanner; } } php-zend-code-3.4.1/test/Reflection/TestAsset/SampleAnnotation.php000066400000000000000000000011171357431215700251410ustar00rootroot00000000000000content = __CLASS__ . ': ' . $content; } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestSampleClass.php000066400000000000000000000003651357431215700247400ustar00rootroot00000000000000 * @method test() * @property $test */ class TestSampleClass10 { /** * Method ShortDescription * * Method LongDescription * This is a long description for * the docblock of this class, it * should be longer than 3 lines. * It indeed is longer than 3 lines * now. * * @param int $one Description for one * @param int Description for two * @param string $three Description for three * which spans multiple lines * @return mixed Some return descr */ public function doSomething($one, $two = 2, $three = 'three') { return 'mixedValue'; } /** * Method ShortDescription * * @param int $one Description for one * @param int Description for two * @param string $three Description for three * which spans multiple lines * @return int */ public function doSomethingElse($one, $two = 2, $three = 'three') { return 'mixedValue'; } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestSampleClass11.php000066400000000000000000000042341357431215700251010ustar00rootroot00000000000000getCacheKey($queryString); // $cachedValue = $this->cache->get($cacheKey); // // if ($cachedValue) { // return $cachedValue; // } // $result = parent::__prototype(); // $this->cache->put($cacheKey, $result); // return $result; // } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestSampleClass12.php000066400000000000000000000010751357431215700251020ustar00rootroot00000000000000 * @copyright Copyright (c) 2011-now AllCode, https://allcode.nl */ namespace ZendTest\Code\Reflection\TestAsset; class TestSampleClass14 { /** * @var string */ public $onlyType; /** * @var string Foo bar */ public $typeDescription; /** * @var string $typeName */ public $typeName; /** * @var string $typeNameDescription Foo bar */ public $typeNameDescription; } php-zend-code-3.4.1/test/Reflection/TestAsset/TestSampleClass2.php000066400000000000000000000010251357431215700250140ustar00rootroot00000000000000_prop1; } public function getProp2($param1, TestSampleClass $param2) { return $this->_prop2; } public function getIterator() { return []; } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestSampleClass3.php000066400000000000000000000007311357431215700250200ustar00rootroot00000000000000 * @method test() * @property $test */ class TestSampleClass5 { /** * Method ShortDescription * * Method LongDescription * This is a long description for * the docblock of this class, it * should be longer than 3 lines. * It indeed is longer than 3 lines * now. * * @param int $one Description for one * @param int Description for two * @param string $three Description for three * which spans multiple lines * @return mixed Some return descr */ public function doSomething($one, $two = 2, $three = 'three', array $array = array(), TestSampleClass $class = null) { return 'mixedValue'; } /** * Method ShortDescription * * @param int $one Description for one * @param int Description for two * @param string $three Description for three * which spans multiple lines * @return int */ public function doSomethingElse($one, $two = 2, $three = 'three') { return 'mixedValue'; } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestSampleClass6.php000066400000000000000000000023721357431215700250260ustar00rootroot00000000000000 */ class TestSampleClass6 { /** * Method ShortDescription * * Notice the multiple spaces aligning the columns in the docblock * tags. (This long description should be longer than 3 lines. * It indeed is longer than 3 lines * now.) * * @emptyTag * @descriptionTag A tag with just a description * @param int $var Description of $var * @return string Description of return value */ public function doSomething($var) { //we need a multi-line method body. $assigned = 1; $alsoAssigined = 2; return 'mixedValue'; } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestSampleClass7.php000066400000000000000000000005401357431215700250220ustar00rootroot00000000000000 */ namespace ZendTest\Code\Reflection\TestAsset; /** * This is a sample class docblock * * @myTag blah */ class TestSampleClass7 { /** * @param Zend\Foo\Bar $var desc * @return Zend\Code\Reflection\DocBlock */ public function doSomething() { } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestSampleClass8.php000066400000000000000000000011541357431215700250250ustar00rootroot00000000000000_prop1; } public function getProp2($param1, TestSampleClass $param2) { return $this->_prop2; } public function getIterator() { return []; } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestSampleClassInterface.php000066400000000000000000000006161357431215700265600ustar00rootroot00000000000000other = $other; } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestTraitClass2.php000066400000000000000000000005231357431215700246600ustar00rootroot00000000000000dummy; } /** * @param bool $autoFetchingAllowed * @return Model_AbstractModel */ public function setDummy($dummy) { $this->dummy = boolval($dummy); return $this; } } php-zend-code-3.4.1/test/Reflection/TestAsset/TestTraitClass3.php000066400000000000000000000001361357431215700246610ustar00rootroot00000000000000 function() { return 'function5'; }); $list2 = array(function() { return 'function6'; }); $list3 = array(function() { return $c = function() { return 'function7'; }; return $c(); }); $function8 = function() use ($list1) { return 'function 8'; }; /** * closure doc block */ $function9 = function() {}; eval("\$function10 = function() { return 'function10'; };"); php-zend-code-3.4.1/test/Reflection/TestAsset/functions.php000066400000000000000000000026311357431215700236770ustar00rootroot00000000000000markTestIncomplete('This test needs to be filled out'); } } php-zend-code-3.4.1/test/Scanner/AnnotationScannerTest.php000066400000000000000000000035071357431215700235360ustar00rootroot00000000000000registerAnnotations([ $foo = new TestAsset\Annotation\Foo(), $bar = new TestAsset\Annotation\Bar(), ]); $annotationManager->attach($parser); $docComment = '/**' . $newLine . ' * @Test\Foo(\'anything I want()' . $newLine . ' * to be\')' . $newLine . ' * @Test\Bar' . $newLine . ' */'; $nameInfo = new NameInformation(); $nameInfo->addUse('ZendTest\Code\Scanner\TestAsset\Annotation', 'Test'); $annotationScanner = new AnnotationScanner($annotationManager, $docComment, $nameInfo); self::assertEquals(get_class($foo), get_class($annotationScanner[0])); self::assertEquals("'anything I want()\n to be'", $annotationScanner[0]->getContent()); self::assertEquals(get_class($bar), get_class($annotationScanner[1])); } public function newLine() { return [ ["\n"], ["\r"], ["\r\n"], ]; } } php-zend-code-3.4.1/test/Scanner/CachingFileScannerTest.php000066400000000000000000000070141357431215700235550ustar00rootroot00000000000000getClassNames()); self::assertEquals(1, $this->getCacheCount($cfs1)); // ensure same class is used internally $cfs2 = new CachingFileScanner(__DIR__ . '/../TestAsset/BarClass.php'); self::assertEquals(1, $this->getCacheCount($cfs2)); self::assertSameInternalFileScanner($cfs1, $cfs2); // ensure $cfs3 = new CachingFileScanner(__DIR__ . '/../TestAsset/FooClass.php'); self::assertEquals(2, $this->getCacheCount($cfs3)); self::assertDifferentInternalFileScanner($cfs2, $cfs3); $annoManager = new AnnotationManager(); $cfs4 = new CachingFileScanner(__DIR__ . '/../TestAsset/FooClass.php', $annoManager); self::assertEquals(3, $this->getCacheCount($cfs4)); self::assertDifferentInternalFileScanner($cfs3, $cfs4); $cfs5 = new CachingFileScanner(__DIR__ . '/../TestAsset/FooClass.php', $annoManager); self::assertEquals(3, $this->getCacheCount($cfs5)); self::assertSameInternalFileScanner($cfs4, $cfs5); $cfs6 = new CachingFileScanner(__DIR__ . '/../TestAsset/BarClass.php', $annoManager); self::assertEquals(4, $this->getCacheCount($cfs6)); self::assertDifferentInternalFileScanner($cfs5, $cfs6); } protected function getCacheCount(CachingFileScanner $cfs) { $r = new \ReflectionObject($cfs); $cacheProp = $r->getProperty('cache'); $cacheProp->setAccessible(true); return count($cacheProp->getValue($cfs)); } protected function assertSameInternalFileScanner(CachingFileScanner $one, CachingFileScanner $two) { $rOne = new \ReflectionObject($one); $fileScannerPropOne = $rOne->getProperty('fileScanner'); $fileScannerPropOne->setAccessible(true); $rTwo = new \ReflectionObject($two); $fileScannerPropTwo = $rTwo->getProperty('fileScanner'); $fileScannerPropTwo->setAccessible(true); self::assertSame($fileScannerPropOne->getValue($one), $fileScannerPropTwo->getValue($two)); } protected function assertDifferentInternalFileScanner(CachingFileScanner $one, CachingFileScanner $two) { $rOne = new \ReflectionObject($one); $fileScannerPropOne = $rOne->getProperty('fileScanner'); $fileScannerPropOne->setAccessible(true); $rTwo = new \ReflectionObject($two); $fileScannerPropTwo = $rTwo->getProperty('fileScanner'); $fileScannerPropTwo->setAccessible(true); self::assertNotSame($fileScannerPropOne->getValue($one), $fileScannerPropTwo->getValue($two)); } } php-zend-code-3.4.1/test/Scanner/ClassScannerTest.php000066400000000000000000000277421357431215700225000ustar00rootroot00000000000000manager = new Annotation\AnnotationManager(); $genericParser = new Annotation\Parser\GenericAnnotationParser(); $genericParser->registerAnnotation(Foo::class); $genericParser->registerAnnotation(Bar::class); $this->manager->attach($genericParser); } public function testClassScannerHasClassInformation() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); self::assertEquals(FooClass::class, $class->getName()); self::assertEquals('FooClass', $class->getShortName()); self::assertFalse($class->isFinal()); self::assertTrue($class->isAbstract()); self::assertFalse($class->isInterface()); $interfaces = $class->getInterfaces(); self::assertContains('ArrayAccess', $interfaces); self::assertContains('A\B\C\D\Blarg', $interfaces); self::assertContains('ZendTest\Code\TestAsset\Local\SubClass', $interfaces); $methods = $class->getMethodNames(); self::assertIsArray($methods); self::assertContains('fooBarBaz', $methods); } public function testClassScannerHasConstant() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); self::assertIsArray($class->getConstantNames()); self::assertContains('FOO', $class->getConstantNames()); } public function testClassScannerHasProperties() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); self::assertContains('bar', $class->getPropertyNames()); } public function testClassScannerHasMethods() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); self::assertContains('fooBarBaz', $class->getMethodNames()); } /** * @todo Remove error handling once we remove deprecation warning from getConstants method */ public function testGetConstantsReturnsConstantNames() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); ErrorHandler::start(E_USER_DEPRECATED); $constants = $class->getConstants(); $error = ErrorHandler::stop(); self::assertInstanceOf(\ErrorException::class, $error); self::assertContains('FOO', $constants); } public function testGetConstantsReturnsInstancesOfConstantScanner() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); $constants = $class->getConstants(false); foreach ($constants as $constant) { self::assertInstanceOf(ConstantScanner::class, $constant); } } public function testHasConstant() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); self::assertTrue($class->hasConstant('FOO')); self::assertFalse($class->hasConstant('foo')); } public function testHasProperty() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); self::assertTrue($class->hasProperty('foo')); self::assertFalse($class->hasProperty('FOO')); self::assertTrue($class->hasProperty('bar')); } public function testHasMethod() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); self::assertTrue($class->hasMethod('fooBarBaz')); self::assertFalse($class->hasMethod('FooBarBaz')); self::assertFalse($class->hasMethod('bar')); } public function testClassScannerReturnsMethodsWithMethodScanners() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); $methods = $class->getMethods(); foreach ($methods as $method) { self::assertInstanceOf(MethodScanner::class, $method); } } public function testClassScannerReturnsPropertiesWithPropertyScanners() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); $properties = $class->getProperties(); foreach ($properties as $property) { self::assertInstanceOf(PropertyScanner::class, $property); } } public function testClassScannerCanScanInterface() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooInterface.php'); $class = $file->getClass(FooInterface::class); self::assertEquals(FooInterface::class, $class->getName()); } public function testClassScannerCanReturnLineNumbers() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); self::assertEquals(11, $class->getLineStart()); self::assertEquals(36, $class->getLineEnd()); $file = new FileScanner(__DIR__ . '/../TestAsset/BarClass.php'); $class = $file->getClass(BarClass::class); self::assertEquals(10, $class->getLineStart()); self::assertEquals(42, $class->getLineEnd()); } public function testClassScannerCanScanAnnotations() { $file = new FileScanner(__DIR__ . '/../Annotation/TestAsset/EntityWithAnnotations.php'); $class = $file->getClass(EntityWithAnnotations::class); $annotations = $class->getAnnotations($this->manager); self::assertTrue($annotations->hasAnnotation(Foo::class)); self::assertTrue($annotations->hasAnnotation(Bar::class)); self::assertEquals('first', $annotations[0]->content); self::assertEquals('second', $annotations[1]->content); self::assertEquals('third', $annotations[2]->content); } /** * @group trait1 */ public function testClassScannerCanScanTraits() { $file = new FileScanner(__DIR__ . '/../TestAsset/BarTrait.php'); $class = $file->getClass(BarTrait::class); self::assertTrue($class->isTrait()); self::assertTrue($class->hasMethod('bar')); } /** * @group trait2 */ public function testClassScannerCanScanClassThatUsesTraits() { $file = new FileScanner(__DIR__ . '/../TestAsset/TestClassUsesTraitSimple.php'); $class = $file->getClass(TestClassUsesTraitSimple::class); self::assertFalse($class->isTrait()); $traitNames = $class->getTraitNames(); $class->getTraitAliases(); self::assertContains(BarTrait::class, $traitNames); self::assertContains(FooTrait::class, $traitNames); self::assertContains(BazTrait::class, $traitNames); } /** * @group trait3 */ public function testClassScannerCanScanClassAndGetTraitsAliases() { $file = new FileScanner(__DIR__ . '/../TestAsset/TestClassWithTraitAliases.php'); $class = $file->getClass(TestClassWithTraitAliases::class); self::assertFalse($class->isTrait()); $aliases = $class->getTraitAliases(); self::assertCount(1, $aliases); self::assertEquals(key($aliases), 'test'); self::assertEquals(current($aliases), 'ZendTest\Code\TestAsset\TraitWithSameMethods::foo'); } /** * @group trait4 */ public function testClassScannerCanGetTraitMethodsInGetMethods() { //load files or test may fail due to autoload issues require_once __DIR__ . '/../TestAsset/TraitWithSameMethods.php'; require_once __DIR__ . '/../TestAsset/BarTrait.php'; $file = new FileScanner(__DIR__ . '/../TestAsset/TestClassWithTraitAliases.php'); $class = $file->getClass(TestClassWithTraitAliases::class); self::assertFalse($class->isTrait()); $testMethods = [ 'fooBarBaz' => 'isPublic', 'foo' => 'isPublic', 'bar' => 'isPublic', 'test' => 'isPrivate', 'bazFooBar' => 'isPublic', ]; self::assertEquals($class->getMethodNames(), array_keys($testMethods)); foreach ($testMethods as $methodName => $testMethod) { self::assertTrue($class->hasMethod($methodName), sprintf('Cannot find method %s', $methodName)); $method = $class->getMethod($methodName); self::assertInstanceOf(MethodScanner::class, $method, $methodName . ' not found.'); self::assertTrue($method->$testMethod()); // test that we got the right ::bar method based on declaration if ($testMethod === 'bar') { self::assertEquals(trim($method->getBody), 'echo "foo";'); } } } /** * @group trait5 */ public function testGetMethodsThrowsExceptionOnDuplicateMethods() { $file = new FileScanner(__DIR__ . '/TestAsset/TestClassWithAliasException.php'); $class = $file->getClass(TestAsset\TestClassWithAliasException::class); $this->expectException(RuntimeException::class); $class->getMethods(); } public function testClassIsInstantiable() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooBarClass.php'); $class = $file->getClass('ZendTest_Code_TestAsset_FooBar'); self::assertFalse($class->isAbstract()); self::assertTrue($class->isInstantiable()); } public function testAbstractClassIsNotInstantiable() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooClass.php'); $class = $file->getClass(FooClass::class); self::assertTrue($class->isAbstract()); self::assertFalse($class->isInstantiable()); } public function testInterfaceIsNotInstantiable() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooInterface.php'); $class = $file->getClass(FooInterface::class); self::assertTrue($class->isInterface()); self::assertFalse($class->isInstantiable()); } public function testTraitIsNotInstantiable() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooTrait.php'); $class = $file->getClass(FooTrait::class); self::assertTrue($class->isTrait()); self::assertFalse($class->isInstantiable()); } public function testGetInterfacesFromInterface() { $file = new FileScanner(__DIR__ . '/../TestAsset/FooInterface.php'); $class = $file->getClass(FooInterface::class); self::assertTrue($class->isInterface()); self::assertCount(1, $class->getInterfaces()); self::assertEquals('ArrayAccess', $class->getInterfaces()[0]); } } php-zend-code-3.4.1/test/Scanner/ConstantScannerTest.php000066400000000000000000000023461357431215700232150ustar00rootroot00000000000000getClass(FooClass::class); $constant = $class->getConstant('BAR'); self::assertEquals('BAR', $constant->getName()); self::assertEquals(5, $constant->getValue()); $constant = $class->getConstant('FOO'); self::assertEquals('FOO', $constant->getName()); self::assertEquals(5, $constant->getValue()); $constant = $class->getConstant('BAZ'); self::assertEquals('BAZ', $constant->getName()); self::assertEquals('baz', $constant->getValue()); self::assertNotNull('Some comment', $constant->getDocComment()); } } php-zend-code-3.4.1/test/Scanner/DerivedClassScannerTest.php000066400000000000000000000016111357431215700237660ustar00rootroot00000000000000addDirectory(__DIR__ . '/TestAsset'); $ads = new AggregateDirectoryScanner(); $ads->addDirectoryScanner($ds); $c = $ads->getClass(TestAsset\MapperExample\RepositoryB::class); self::assertEquals(TestAsset\MapperExample\RepositoryB::class, $c->getName()); } } php-zend-code-3.4.1/test/Scanner/DocBlockScannerTest.php000066400000000000000000000035031357431215700231000ustar00rootroot00000000000000getTags(); self::assertCount(1, $tags); self::assertArrayHasKey('name', $tags[0]); self::assertEquals('@mytag', $tags[0]['name']); self::assertArrayHasKey('value', $tags[0]); self::assertEquals('', $tags[0]['value']); } public function testDocBlockScannerDescriptions() { $docComment = <<getShortDescription()); self::assertEquals('Long Description continued in the second line', $tokenScanner->getLongDescription()); // windows-style line separators $docComment = str_replace("\n", "\r\n", $docComment); $tokenScanner = new DocBlockScanner($docComment); self::assertEquals('Short Description', $tokenScanner->getShortDescription()); self::assertEquals('Long Description continued in the second line', $tokenScanner->getLongDescription()); } } php-zend-code-3.4.1/test/Scanner/FileScannerTest.php000066400000000000000000000014531357431215700223010ustar00rootroot00000000000000getClass(Baz::class)->getName()); self::assertEquals('Foo', $tokenScanner->getClass('Foo')->getName()); } } php-zend-code-3.4.1/test/Scanner/MethodScannerTest.php000066400000000000000000000121421357431215700226370ustar00rootroot00000000000000getClass(FooClass::class); $method = $class->getMethod('fooBarBaz'); self::assertEquals('fooBarBaz', $method->getName()); self::assertFalse($method->isAbstract()); self::assertTrue($method->isFinal()); self::assertTrue($method->isPublic()); self::assertFalse($method->isProtected()); self::assertFalse($method->isPrivate()); self::assertFalse($method->isStatic()); } public function testMethodScannerReturnsParameters() { $file = new FileScanner(__DIR__ . '/../TestAsset/BarClass.php'); $class = $file->getClass(BarClass::class); $method = $class->getMethod('three'); $parameters = $method->getParameters(); self::assertIsArray($parameters); } public function testMethodScannerReturnsParameterScanner() { $file = new FileScanner(__DIR__ . '/../TestAsset/BarClass.php'); $class = $file->getClass(BarClass::class); $method = $class->getMethod('three'); self::assertEquals(['o', 't', 'bbf'], $method->getParameters()); $parameter = $method->getParameter('t'); self::assertInstanceOf(ParameterScanner::class, $parameter); self::assertEquals('t', $parameter->getName()); } public function testMethodScannerParsesClassNames() { $file = new FileScanner(__DIR__ . '/../TestAsset/BarClass.php'); $class = $file->getClass(BarClass::class); $method = $class->getMethod('five'); self::assertEquals(['a'], $method->getParameters()); $parameter = $method->getParameter('a'); self::assertEquals(AbstractClass::class, $parameter->getClass()); } public function testMethodScannerReturnsPropertyWithNoDefault() { $file = new FileScanner(__DIR__ . '/../TestAsset/BazClass.php'); $class = $file->getClass('BazClass'); $method = $class->getMethod('__construct'); self::assertTrue($method->isPublic()); } public function testMethodScannerReturnsLineNumbersForMethods() { $file = new FileScanner(__DIR__ . '/../TestAsset/BarClass.php'); $class = $file->getClass(BarClass::class); $method = $class->getMethod('three'); self::assertEquals(27, $method->getLineStart()); self::assertEquals(31, $method->getLineEnd()); } public function testMethodScannerReturnsBodyMethods() { $file = new FileScanner(__DIR__ . '/../TestAsset/BarClass.php'); $class = $file->getClass(BarClass::class); $method = $class->getMethod('three'); $expected = "\n" . ' $x = 5 + 5;' . "\n" . ' $y = \'this string\';' . "\n "; self::assertEquals($expected, $method->getBody()); } public function testMethodScannerMethodSignatureLatestOptionalParamHasParentheses() { $file = new FileScanner(__DIR__ . '/../TestAsset/BarClass.php'); $class = $file->getClass(BarClass::class); $method = $class->getMethod('four'); $paramTwo = $method->getParameter(1); $optionalValue = $paramTwo->getDefaultValue(); self::assertEquals('array([array(\'default\')])', $optionalValue); } /** * @group issue-6893 */ public function testMethodScannerWorksWithSingleAbstractFunction() { $file = new FileScanner(__DIR__ . '/../TestAsset/AbstractClass.php'); $class = $file->getClass(AbstractClass::class); $method = $class->getMethod('helloWorld'); self::assertTrue($method->isAbstract()); } public function testMethodScannerSetVisibilityThrowsInvalidArgumentException() { $methodScanner = new MethodScanner([]); // make sure test argument is invalid $invalidArgument = max(T_PUBLIC, T_PROTECTED, T_PRIVATE) + 1; $this->expectException('\Zend\Code\Exception\InvalidArgumentException'); $methodScanner->setVisibility($invalidArgument); } public function testMethodScannerSetVisibilityAcceptsIntegerTokens() { $methodScanner = new MethodScanner([]); $this->assertSame($methodScanner->setVisibility(T_PUBLIC), $methodScanner); $this->assertSame($methodScanner->setVisibility(T_PROTECTED), $methodScanner); $this->assertSame($methodScanner->setVisibility(T_PRIVATE), $methodScanner); } } php-zend-code-3.4.1/test/Scanner/ParameterScannerTest.php000066400000000000000000000025241357431215700233420ustar00rootroot00000000000000getClass(BarClass::class); $method = $class->getMethod('three'); $parameter = $method->getParameter('t'); self::assertEquals(BarClass::class, $parameter->getDeclaringClass()); self::assertEquals('three', $parameter->getDeclaringFunction()); self::assertEquals('t', $parameter->getName()); self::assertEquals(2, $parameter->getPosition()); self::assertEquals('2', $parameter->getDefaultValue()); self::assertFalse($parameter->isArray()); self::assertTrue($parameter->isDefaultValueAvailable()); self::assertTrue($parameter->isOptional()); self::assertTrue($parameter->isPassedByReference()); } } php-zend-code-3.4.1/test/Scanner/PropertyScannerTest.php000066400000000000000000000106271357431215700232510ustar00rootroot00000000000000getClass(FooClass::class); $property = $class->getProperty('bar'); self::assertEquals('bar', $property->getName()); self::assertEquals('value', $property->getValue()); self::assertFalse($property->isPublic()); self::assertTrue($property->isProtected()); self::assertFalse($property->isPrivate()); self::assertTrue($property->isStatic()); $property = $class->getProperty('foo'); self::assertEquals('foo', $property->getName()); self::assertEquals('value2', $property->getValue()); self::assertTrue($property->isPublic()); self::assertFalse($property->isProtected()); self::assertFalse($property->isPrivate()); self::assertFalse($property->isStatic()); $property = $class->getProperty('baz'); self::assertEquals('baz', $property->getName()); self::assertEquals(3, $property->getValue()); self::assertFalse($property->isPublic()); self::assertFalse($property->isProtected()); self::assertTrue($property->isPrivate()); self::assertFalse($property->isStatic()); } /** * @group 5384 */ public function testPropertyScannerReturnsProperValue() { $class = <<<'CLASS' 2,2); private $arraynew = ['test' => 2,2]; private $notarray = "['test' => 2,2]"; private $status = false; } CLASS; $tokenScanner = new TokenArrayScanner(token_get_all($class)); $fooClass = $tokenScanner->getClass('Foo'); foreach ($fooClass->getProperties() as $property) { $value = $property->getValue(); $valueType = $property->getValueType(); switch ($property->getName()) { case 'empty': self::assertNull($value); self::assertEquals('unknown', $valueType); break; case 'string': self::assertEquals('string', $value); self::assertEquals('string', $valueType); break; case 'int': self::assertEquals('123', $value); self::assertEquals('int', $valueType); break; case 'array': self::assertEquals("array('test'=>2,2)", $value); self::assertEquals('array', $valueType); break; case 'arraynew': self::assertEquals("['test'=>2,2]", $value); self::assertEquals('array', $valueType); break; case 'notarray': self::assertEquals('string', $valueType); break; case 'status': self::assertEquals('false', $value); self::assertEquals('boolean', $valueType); break; } } } /** * @group issue-8 */ public function testPropertyScannerReturnsProperValueRegardlessOfOrder() { $class = <<<'CLASS' getClass('Foo'); $property = $class->getProperty('string'); self::assertEquals('string', $property->getValue()); self::assertEquals('string', $property->getValueType()); $property = $class->getProperty('int'); self::assertEquals('int', $property->getValueType()); self::assertEquals(123, $property->getValue()); } } php-zend-code-3.4.1/test/Scanner/TestAsset/000077500000000000000000000000001357431215700204535ustar00rootroot00000000000000php-zend-code-3.4.1/test/Scanner/TestAsset/Annotation/000077500000000000000000000000001357431215700225655ustar00rootroot00000000000000php-zend-code-3.4.1/test/Scanner/TestAsset/Annotation/Bar.php000066400000000000000000000011011357431215700237730ustar00rootroot00000000000000content = $content; } } php-zend-code-3.4.1/test/Scanner/TestAsset/Annotation/Foo.php000066400000000000000000000012171357431215700240220ustar00rootroot00000000000000content = $content; } public function getContent() { return $this->content; } } php-zend-code-3.4.1/test/Scanner/TestAsset/MapperExample/000077500000000000000000000000001357431215700232135ustar00rootroot00000000000000php-zend-code-3.4.1/test/Scanner/TestAsset/MapperExample/DbAdapter.php000066400000000000000000000014751357431215700255610ustar00rootroot00000000000000username = $username; $this->password = $password; } public function __toString() { return 'I am ' . get_class($this) . ' object (hash ' . spl_object_hash($this) . '), with these parameters (username = ' . $this->username . ', password = ' . $this->password . ')'; } } php-zend-code-3.4.1/test/Scanner/TestAsset/MapperExample/EntityA.php000066400000000000000000000010531357431215700253000ustar00rootroot00000000000000dbAdapter = $dbAdapter; } public function __toString() { return 'I am a ' . get_class($this) . ' object (hash ' . spl_object_hash($this) . '), using this dbAdapter ' . "\n" . ' ' . $this->dbAdapter; } } php-zend-code-3.4.1/test/Scanner/TestAsset/MapperExample/RepositoryA.php000066400000000000000000000020401357431215700262000ustar00rootroot00000000000000mapper = $mapper; } public function find(/* $entityCriterion */) { // so something with criterion /* $data = $mapper->findByCriterion($entityCriterion); $entity = new EntityA(); populate($entity); return $entity; */ return new EntityA; } public function __toString() { return 'I am a ' . get_class($this) . ' object (hash ' . spl_object_hash($this) . '), using this mapper object ' . "\n" . ' ' . $this->mapper; } } php-zend-code-3.4.1/test/Scanner/TestAsset/MapperExample/RepositoryB.php000066400000000000000000000007211357431215700262050ustar00rootroot00000000000000hasNamespace('ZendTest\Code\TestAsset')); $namespaces = $tokenScanner->getNamespaces(); self::assertIsArray($namespaces); self::assertContains('ZendTest\Code\TestAsset', $namespaces); } public function testScannerReturnsNamespacesInNotNamespacedClasses() { $tokenScanner = new TokenArrayScanner(token_get_all( file_get_contents(__DIR__ . '/../TestAsset/FooBarClass.php') )); $uses = $tokenScanner->getUses(); self::assertIsArray($uses); $foundUses = []; foreach ($uses as $use) { $foundUses[] = $use['use']; } self::assertContains('ArrayObject', $foundUses); } public function testScannerReturnsClassNames() { $tokenScanner = new TokenArrayScanner(token_get_all( file_get_contents(__DIR__ . '/../TestAsset/FooClass.php') )); $classes = $tokenScanner->getClassNames(); self::assertIsArray($classes); self::assertContains(FooClass::class, $classes); } /** * @group gh-4989 */ public function testScannerReturnsClassNamesForTraits() { $tokenScanner = new TokenArrayScanner(token_get_all( file_get_contents(__DIR__ . '/../TestAsset/FooTrait.php') )); $classes = $tokenScanner->getClassNames(); self::assertIsArray($classes); self::assertContains(FooTrait::class, $classes); } public function testScannerReturnsFunctions() { $tokenScanner = new TokenArrayScanner(token_get_all( file_get_contents(__DIR__ . '/../TestAsset/functions.php') )); $functions = $tokenScanner->getFunctionNames(); self::assertIsArray($functions); self::assertContains('ZendTest\Code\TestAsset\foo_bar', $functions); } public function testScannerReturnsClassScanner() { $tokenScanner = new TokenArrayScanner(token_get_all( file_get_contents(__DIR__ . '/../TestAsset/FooClass.php') )); $classes = $tokenScanner->getClasses(); self::assertIsArray($classes); foreach ($classes as $class) { self::assertInstanceOf(ClassScanner::class, $class); } } public function testScannerCanHandleMultipleNamespaceFile() { $tokenScanner = new TokenArrayScanner(token_get_all( file_get_contents(__DIR__ . '/../TestAsset/MultipleNamespaces.php') )); self::assertEquals(Baz::class, $tokenScanner->getClass(Baz::class)->getName()); self::assertEquals('Foo', $tokenScanner->getClass('Foo')->getName()); } } php-zend-code-3.4.1/test/TestAsset/000077500000000000000000000000001357431215700170625ustar00rootroot00000000000000php-zend-code-3.4.1/test/TestAsset/AbstractClass.php000066400000000000000000000010161357431215700223220ustar00rootroot00000000000000config; } abstract public function helloWorld(); } php-zend-code-3.4.1/test/TestAsset/BarClass.php000066400000000000000000000013421357431215700212650ustar00rootroot00000000000000cfs = $cfs; } public function getCache() { } } php-zend-code-3.4.1/test/TestAsset/ReturnTypeHintedClass.php000066400000000000000000000013341357431215700240370ustar00rootroot00000000000000