diff --git a/.gitignore b/.gitignore index a056307..75137f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -testing/logs \ No newline at end of file +testing/logs +vendor diff --git a/composer.json b/composer.json index a7f00bd..6439b7c 100644 --- a/composer.json +++ b/composer.json @@ -34,5 +34,8 @@ "psr-4": { "SciActive\\": "src/" } - } + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..ef82dd5 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1470 @@ +{ + "_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#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "80f6d13654aafcd55beb46664d434d6a", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" + }, + "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://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2017-07-22T11:58:36+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^4.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": "2017-10-19T19:58:43+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "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": "2017-03-05T18:14:27+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "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": "2017-03-05T17:38:23+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.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": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "4.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2d3d238c433cf69caeb4842e97a3223a116f94b2", + "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2", + "shasum": "" + }, + "require": { + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "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": "2017-08-30T18:51:59+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.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" + } + ], + "time": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.7.2", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", + "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8 || ^5.6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "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": "2017-09-04T11:05:03+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "5.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/8ed1902a57849e117b5651fc1a5c48110946c06b", + "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.0", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^1.4.11 || ^2.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "ext-xdebug": "^2.5", + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-xdebug": "^2.5.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.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": "2017-08-03T12:40:43+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.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": "2016-10-03T07:40:28+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": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9a02332089ac48e704c70f6cefed30c224e3c0b0", + "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2.4" + }, + "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": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2017-08-20T05:47:52+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "6.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "06b28548fd2b4a20c3cd6e247dc86331a7d4db13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/06b28548fd2b4a20c3cd6e247dc86331a7d4db13", + "reference": "06b28548fd2b4a20c3cd6e247dc86331a7d4db13", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.6.1", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.0", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^5.2.2", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^1.0.9", + "phpunit/phpunit-mock-objects": "^4.0.3", + "sebastian/comparator": "^2.0.2", + "sebastian/diff": "^2.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2", + "phpunit/dbunit": "<3.0" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "^1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.4.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": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2017-10-16T13:18:59+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "2f789b59ab89669015ad984afa350c4ec577ade0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/2f789b59ab89669015ad984afa350c4ec577ade0", + "reference": "2f789b59ab89669015ad984afa350c4ec577ade0", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.5", + "php": "^7.0", + "phpunit/php-text-template": "^1.2.1", + "sebastian/exporter": "^3.0" + }, + "conflict": { + "phpunit/phpunit": "<6.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2017-08-03T14:08:16+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": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "ae068fede81d06e7bb9bb46a367210a3d3e1fe6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/ae068fede81d06e7bb9bb46a367210a3d3e1fe6a", + "reference": "ae068fede81d06e7bb9bb46a367210a3d3e1fe6a", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/diff": "^2.0", + "sebastian/exporter": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "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": "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": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-08-03T07:14:59+00:00" + }, + { + "name": "sebastian/diff", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "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": "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" + ], + "time": "2017-08-03T08:09:46+00:00" + }, + { + "name": "sebastian/environment", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "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" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2017-07-01T08:51:00+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "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": "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" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2017-04-03T13:19:02+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "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": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2017-04-27T15:39:26+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": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.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": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+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": "theseer/tokenizer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "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": "2017-04-07T12:08:54+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "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": "2016-11-23T20:04:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/src/Hook.php b/src/Hook.php index 0eca341..ee1f445 100644 --- a/src/Hook.php +++ b/src/Hook.php @@ -1,4 +1,6 @@ -". - * @param bool $recursive Whether to hook objects recursively. - * @return bool True on success, false on failure. - */ - public static function hookObject(&$object, $prefix = '', $recursive = true) { - if ((object) $object === $object) { - $isString = false; - } else { - $isString = true; - } + /** + * Hook an object. + * + * This hooks all (public) methods defined in the given object. + * + * @param object &$object The object to hook. + * @param string $prefix The prefix used to call the object's methods. Usually something like "$object->". + * @param bool $recursive Whether to hook objects recursively. + * @return bool True on success, false on failure. + */ + public static function hookObject(&$object, $prefix = '', $recursive = true) { + if ((object) $object === $object) { + $isString = false; + } else { + $isString = true; + } - // Make sure we don't take over the hook object, or we'll end up - // recursively calling ourself. Some system classes shouldn't be hooked. - $className = str_replace('\\', '_', $isString ? $object : get_class($object)); - global $_; - if (isset($_) && in_array($className, array('\SciActive\Hook', 'depend', 'config', 'info'))) { - return false; - } + // Make sure we don't take over the hook object, or we'll end up + // recursively calling ourself. Some system classes shouldn't be hooked. + $className = str_replace('\\', '_', $isString ? $object : get_class($object)); + global $_; + if (isset($_) && in_array($className, array('\SciActive\Hook', 'depend', 'config', 'info'))) { + return false; + } - if ($recursive && !$isString) { - foreach ($object as $curName => &$curProperty) { - if ((object) $curProperty === $curProperty) { - Hook::hookObject($curProperty, $prefix.$curName.'->'); - } - } + if ($recursive && !$isString) { + foreach ($object as $curName => &$curProperty) { + if ((object) $curProperty === $curProperty) { + Hook::hookObject($curProperty, $prefix.$curName.'->'); } + } + } - if (!class_exists("\SciActive\HookOverride_$className")) { - if ($isString) { - $reflection = new \ReflectionClass($object); - } else { - $reflection = new \ReflectionObject($object); - } - $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); - - $code = ''; - foreach ($methods as &$curMethod) { - $fname = $curMethod->getName(); - if (in_array($fname, array('__construct', '__destruct', '__get', '__set', '__isset', '__unset', '__toString', '__invoke', '__set_state', '__clone', '__sleep', 'jsonSerialize'))) { - continue; - } + if (!class_exists("\SciActive\HookOverride_$className")) { + if ($isString) { + $reflection = new \ReflectionClass($object); + } else { + $reflection = new \ReflectionObject($object); + } + $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); - //$fprefix = $curMethod->isFinal() ? 'final ' : ''; - $fprefix = $curMethod->isStatic() ? 'static ' : ''; - $params = $curMethod->getParameters(); - $paramArray = $paramNameArray = array(); - foreach ($params as &$curParam) { - $paramName = $curParam->getName(); - $paramPrefix = $curParam->isPassedByReference() ? '&' : ''; - if ($curParam->isDefaultValueAvailable()) { - $paramSuffix = ' = '.var_export($curParam->getDefaultValue(), true); - } else { - $paramSuffix = ''; - } - $paramArray[] = "{$paramPrefix}\${$paramName}{$paramSuffix}"; - $paramNameArray[] = "{$paramPrefix}\${$paramName}"; - } - unset($curParam); - $code .= $fprefix."function $fname(".implode(', ', $paramArray).") {\n" - .(defined('HHVM_VERSION') ? - ( - // There is bad behavior in HHVM where debug_backtrace - // won't return arguments, but calling func_get_args - // somewhere in the function changes that behavior to be - // consistent with official PHP. However, it also - // returns arguments by value, instead of by reference. - // So, we must use a more direct method. - " \$arguments = array();\n" - .(count($paramNameArray) > 0 ? - " \$arguments[] = ".implode('; $arguments[] = ', $paramNameArray).";\n" : - '' - ) - ." \$real_arg_count = func_num_args();\n" - ." \$arg_count = count(\$arguments);\n" - ." if (\$real_arg_count > \$arg_count) {\n" - ." for (\$i = \$arg_count; \$i < \$real_arg_count; \$i++)\n" - ." \$arguments[] = func_get_arg(\$i);\n" - ." }\n" - ) : ( - // We must use a debug_backtrace, because that's the - // best way to get all the passed arguments, by - // reference. 5.4 and up lets us limit it to 1 frame. - (version_compare(PHP_VERSION, '5.4.0') >= 0 ? - " \$arguments = debug_backtrace(false, 1);\n" : - " \$arguments = debug_backtrace(false);\n" - ) - ." \$arguments = \$arguments[0]['args'];\n" - ) - ) - ." \$function = array(\$this->_hookObject, '$fname');\n" - ." \$data = array();\n" - ." \\SciActive\\Hook::runCallbacks(\$this->_hookPrefix.'$fname', \$arguments, 'before', \$this->_hookObject, \$function, \$data);\n" - ." if (\$arguments !== false) {\n" - ." \$return = call_user_func_array(\$function, \$arguments);\n" - ." if ((object) \$return === \$return && get_class(\$return) === '$className')\n" - ." \\SciActive\\Hook::hookObject(\$return, '$prefix', false);\n" - ." \$return = array(\$return);\n" - ." \\SciActive\\Hook::runCallbacks(\$this->_hookPrefix.'$fname', \$return, 'after', \$this->_hookObject, \$function, \$data);\n" - ." if ((array) \$return === \$return)\n" - ." return \$return[0];\n" - ." }\n" - ."}\n\n"; - } - unset($curMethod); - // Build a HookOverride class. - $include = str_replace(array('_NAMEHERE_', '//#CODEHERE#', ''), array($className, $code, '', ''), Hook::$hookFile); - eval($include); + $code = ''; + foreach ($methods as &$curMethod) { + $fname = $curMethod->getName(); + if (in_array($fname, array('__construct', '__destruct', '__get', '__set', '__isset', '__unset', '__toString', '__invoke', '__set_state', '__clone', '__sleep', 'jsonSerialize'))) { + continue; } - eval('$object = new \SciActive\HookOverride_'.$className.' ($object, $prefix);'); - return true; + //$fprefix = $curMethod->isFinal() ? 'final ' : ''; + $fprefix = $curMethod->isStatic() ? 'static ' : ''; + $params = $curMethod->getParameters(); + $paramArray = $paramNameArray = array(); + foreach ($params as &$curParam) { + $paramName = $curParam->getName(); + $paramPrefix = $curParam->isPassedByReference() ? '&' : ''; + if ($curParam->isDefaultValueAvailable()) { + $paramSuffix = ' = '.var_export($curParam->getDefaultValue(), true); + } else { + $paramSuffix = ''; + } + $paramArray[] = "{$paramPrefix}\${$paramName}{$paramSuffix}"; + $paramNameArray[] = "{$paramPrefix}\${$paramName}"; + } + unset($curParam); + $code .= $fprefix."function $fname(".implode(', ', $paramArray).") {\n" + .(defined('HHVM_VERSION') ? + ( + // There is bad behavior in HHVM where debug_backtrace + // won't return arguments, but calling func_get_args + // somewhere in the function changes that behavior to be + // consistent with official PHP. However, it also + // returns arguments by value, instead of by reference. + // So, we must use a more direct method. + " \$arguments = array();\n" + .(count($paramNameArray) > 0 ? + " \$arguments[] = ".implode('; $arguments[] = ', $paramNameArray).";\n" : + '' + ) + ." \$real_arg_count = func_num_args();\n" + ." \$arg_count = count(\$arguments);\n" + ." if (\$real_arg_count > \$arg_count) {\n" + ." for (\$i = \$arg_count; \$i < \$real_arg_count; \$i++)\n" + ." \$arguments[] = func_get_arg(\$i);\n" + ." }\n" + ) : ( + // We must use a debug_backtrace, because that's the + // best way to get all the passed arguments, by + // reference. 5.4 and up lets us limit it to 1 frame. + (version_compare(PHP_VERSION, '5.4.0') >= 0 ? + " \$arguments = debug_backtrace(false, 1);\n" : + " \$arguments = debug_backtrace(false);\n" + ) + ." \$arguments = \$arguments[0]['args'];\n" + ) + ) + ." \$function = array(\$this->_hookObject, '$fname');\n" + ." \$data = array();\n" + ." \\SciActive\\Hook::runCallbacks(\$this->_hookPrefix.'$fname', \$arguments, 'before', \$this->_hookObject, \$function, \$data);\n" + ." if (\$arguments !== false) {\n" + ." \$return = call_user_func_array(\$function, \$arguments);\n" + ." if ((object) \$return === \$return && get_class(\$return) === '$className')\n" + ." \\SciActive\\Hook::hookObject(\$return, '$prefix', false);\n" + ." \$return = array(\$return);\n" + ." \\SciActive\\Hook::runCallbacks(\$this->_hookPrefix.'$fname', \$return, 'after', \$this->_hookObject, \$function, \$data);\n" + ." if ((array) \$return === \$return)\n" + ." return \$return[0];\n" + ." }\n" + ."}\n\n"; + } + unset($curMethod); + // Build a HookOverride class. + $include = str_replace(array('_NAMEHERE_', '//#CODEHERE#', ''), array($className, $code, '', ''), Hook::$hookFile); + eval($include); } - /** - * Run the callbacks for a given hook. - * - * Each callback is run and passed the array of arguments, and the name of - * the given hook. If any callback changes $arguments to FALSE, the - * following callbacks will not be called, and FALSE will be returned. - * - * @param string $name The name of the hook. - * @param array &$arguments An array of arguments to be passed to the callbacks. - * @param string $type The type of callbacks to run. 'before', 'after', or 'all'. - * @param mixed &$object The object on which the hook was called. - * @param callback &$function The function which is called at "0". You can change this in the "before" callbacks to effectively takeover a function. - * @param array &$data A data array for callback communication. - */ - public static function runCallbacks($name, &$arguments = array(), $type = 'all', &$object = null, &$function = null, &$data = array()) { - if (isset(Hook::$hooks['all'])) { - foreach (Hook::$hooks['all'] as $curCallback) { - if (($type == 'all' && $curCallback[0] != 0) || ($type == 'before' && $curCallback[0] < 0) || ($type == 'after' && $curCallback[0] > 0)) { - call_user_func_array($curCallback[1], array(&$arguments, $name, &$object, &$function, &$data)); - if ($arguments === false) { - return; - } - } - } - } - if (isset(Hook::$hooks[$name])) { - foreach (Hook::$hooks[$name] as $curCallback) { - if (($type == 'all' && $curCallback[0] != 0) || ($type == 'before' && $curCallback[0] < 0) || ($type == 'after' && $curCallback[0] > 0)) { - call_user_func_array($curCallback[1], array(&$arguments, $name, &$object, &$function, &$data)); - if ($arguments === false) { - return; - } - } - } + eval('$object = new \SciActive\HookOverride_'.$className.' ($object, $prefix);'); + return true; + } + + /** + * Run the callbacks for a given hook. + * + * Each callback is run and passed the array of arguments, and the name of + * the given hook. If any callback changes $arguments to FALSE, the + * following callbacks will not be called, and FALSE will be returned. + * + * @param string $name The name of the hook. + * @param array &$arguments An array of arguments to be passed to the callbacks. + * @param string $type The type of callbacks to run. 'before', 'after', or 'all'. + * @param mixed &$object The object on which the hook was called. + * @param callback &$function The function which is called at "0". You can change this in the "before" callbacks to effectively takeover a function. + * @param array &$data A data array for callback communication. + */ + public static function runCallbacks($name, &$arguments = array(), $type = 'all', &$object = null, &$function = null, &$data = array()) { + if (isset(Hook::$hooks['all'])) { + foreach (Hook::$hooks['all'] as $curCallback) { + if (($type == 'all' && $curCallback[0] != 0) || ($type == 'before' && $curCallback[0] < 0) || ($type == 'after' && $curCallback[0] > 0)) { + call_user_func_array($curCallback[1], array(&$arguments, $name, &$object, &$function, &$data)); + if ($arguments === false) { + return; + } } + } } - - /** - * Sort function for callback sorting. - * - * This assures that callbacks are executed in the correct order. Callback - * IDs are preserved as long as uasort() is used. - * - * @param array $a The first callback in the comparison. - * @param arary $b The second callback in the comparison. - * @return int 0 for equal, -1 for less than, 1 for greater than. - * @access private - */ - private static function sortCallbacks($a, $b) { - if ($a[0] == $b[0]) { - return 0; + if (isset(Hook::$hooks[$name])) { + foreach (Hook::$hooks[$name] as $curCallback) { + if (($type == 'all' && $curCallback[0] != 0) || ($type == 'before' && $curCallback[0] < 0) || ($type == 'after' && $curCallback[0] > 0)) { + call_user_func_array($curCallback[1], array(&$arguments, $name, &$object, &$function, &$data)); + if ($arguments === false) { + return; + } } - return ($a[0] < $b[0]) ? -1 : 1; + } } + } - public static function getHookFile() { - Hook::$hookFile = file_get_contents(__DIR__.DIRECTORY_SEPARATOR.'HookOverride_extend.php'); + /** + * Sort function for callback sorting. + * + * This assures that callbacks are executed in the correct order. Callback + * IDs are preserved as long as uasort() is used. + * + * @param array $a The first callback in the comparison. + * @param array $b The second callback in the comparison. + * @return int 0 for equal, -1 for less than, 1 for greater than. + * @access private + */ + private static function sortCallbacks($a, $b) { + if ($a[0] == $b[0]) { + return 0; } + return ($a[0] < $b[0]) ? -1 : 1; + } + + public static function getHookFile() { + Hook::$hookFile = file_get_contents(__DIR__.DIRECTORY_SEPARATOR.'HookOverride_extend.php'); + } } Hook::getHookFile(); diff --git a/src/HookOverride.php b/src/HookOverride.php index f3413a2..aa1b056 100644 --- a/src/HookOverride.php +++ b/src/HookOverride.php @@ -1,4 +1,6 @@ -_hookObject; - } + public function _hookObject() { + return $this->_hookObject; + } - public function __construct(&$object, $prefix = '') { - $this->_hookObject = $object; - $this->_hookPrefix = $prefix; - } + public function __construct(&$object, $prefix = '') { + $this->_hookObject = $object; + $this->_hookPrefix = $prefix; + } - public function &__get($name) { - $val =& $this->_hookObject->$name; - return $val; - } + public function &__get($name) { + $val =& $this->_hookObject->$name; + return $val; + } - public function __set($name, $value) { - return $this->_hookObject->$name = $value; - } + public function __set($name, $value) { + return $this->_hookObject->$name = $value; + } - public function __isset($name) { - return isset($this->_hookObject->$name); - } + public function __isset($name) { + return isset($this->_hookObject->$name); + } - public function __unset($name) { - unset($this->_hookObject->$name); - } + public function __unset($name) { + unset($this->_hookObject->$name); + } - public function __toString() { - return (string) $this->_hookObject; - } + public function __toString() { + return (string) $this->_hookObject; + } - public function __invoke() { - if (method_exists($this->_hookObject, '__invoke')) { - $args = func_get_args(); - return call_user_func_array(array($this->_hookObject, '__invoke'), $args); - } + public function __invoke() { + if (method_exists($this->_hookObject, '__invoke')) { + $args = func_get_args(); + return call_user_func_array(array($this->_hookObject, '__invoke'), $args); } + } - public function __set_state() { - if (method_exists($this->_hookObject, '__set_state')) { - $args = func_get_args(); - return call_user_func_array(array($this->_hookObject, '__set_state'), $args); - } + public function __set_state() { + if (method_exists($this->_hookObject, '__set_state')) { + $args = func_get_args(); + return call_user_func_array(array($this->_hookObject, '__set_state'), $args); } + } - public function __clone() { - // TODO: Test this. Make sure cloning works properly. - $newObject = clone $this->_hookObject; - Hook::hookObject($newObject, get_class($newObject).'->', false); - return $newObject; - } + public function __clone() { + // TODO: Test this. Make sure cloning works properly. + $newObject = clone $this->_hookObject; + Hook::hookObject($newObject, get_class($newObject).'->', false); + return $newObject; + } - public function jsonSerialize() { - if (is_callable($this->_hookObject, 'jsonSerialize')) { - $args = func_get_args(); - return call_user_func_array(array($this->_hookObject, 'jsonSerialize'), $args); - } else { - return $this->_hookObject; - } + public function jsonSerialize() { + if (is_callable($this->_hookObject, 'jsonSerialize')) { + $args = func_get_args(); + return call_user_func_array(array($this->_hookObject, 'jsonSerialize'), $args); + } else { + return $this->_hookObject; } + } //#CODEHERE# -} \ No newline at end of file +} diff --git a/testing/TestModel.php b/testing/TestModel.php index 5b3b056..8487fa1 100644 --- a/testing/TestModel.php +++ b/testing/TestModel.php @@ -1,13 +1,17 @@ '); - $this->assertInstanceOf('\SciActive\HookOverride_TestModel', $testModel); +class HookTest extends \PHPUnit\Framework\TestCase { + public function testHooking() { + $testModel = new TestModel; + Hook::hookObject($testModel, 'TestModel->'); + $this->assertInstanceOf('\SciActive\HookOverride_TestModel', $testModel); - return $testModel; - } + return $testModel; + } - /** - * @depends testHooking - */ - public function testObjectAccess($testModel) { - $that = $this; - $ids = Hook::addCallback('TestModel->testFunction', -2, function(&$arguments, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals('right', $object->test); - $that->assertEquals('TestModel->testFunction', $name); - }); - $this->assertTrue($testModel->testFunction(true)); - $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); - } + /** + * @depends testHooking + */ + public function testObjectAccess($testModel) { + $that = $this; + $ids = Hook::addCallback('TestModel->testFunction', -2, function(&$arguments, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals('right', $object->test); + $that->assertEquals('TestModel->testFunction', $name); + }); + $this->assertTrue($testModel->testFunction(true)); + $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); + } - /** - * @depends testHooking - */ - public function testFunctionOverride($testModel) { - $ids = Hook::addCallback('TestModel->testFunction', -1, function(&$arguments, $name, &$object, &$function, &$data){ - $function = array($object, 'testFunctionFake'); - }); - $this->assertFalse($testModel->testFunction(true)); - $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); - } + /** + * @depends testHooking + */ + public function testPassByReference($testModel) { + $that = $this; + $ids = Hook::addCallback('TestModel->testReferenceFunction', -2, function(&$arguments, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals('right', $object->test); + $that->assertEquals('TestModel->testReferenceFunction', $name); + }); + $arg = ['data' => true]; + $this->assertEquals($testModel->testReferenceFunction($arg), $arg); + $this->assertTrue($arg['data']); + $this->assertEquals(1, Hook::delCallbackByID('TestModel->testReferenceFunction', $ids[0])); + } - /** - * @depends testHooking - */ - public function testReturnValues($testModel) { - $that = $this; - $ids = Hook::addCallback('TestModel->testFunction', 2, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals('success', $return[0]); - }); - $testModel->testFunction('success'); - $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); - } + /** + * @depends testHooking + */ + public function testFunctionOverride($testModel) { + $ids = Hook::addCallback('TestModel->testFunction', -1, function(&$arguments, $name, &$object, &$function, &$data) { + $function = array($object, 'testFunctionFake'); + }); + $this->assertFalse($testModel->testFunction(true)); + $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); + } - /** - * @depends testHooking - */ - public function testArgumentModification($testModel) { - $ids = Hook::addCallback('TestModel->testFunction', -1, function(&$arguments, $name, &$object, &$function, &$data){ - $arguments[0] = 'success'; - }); - $this->assertEquals('success', $testModel->testFunction(true)); - $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); - } + /** + * @depends testHooking + */ + public function testReturnValues($testModel) { + $that = $this; + $ids = Hook::addCallback('TestModel->testFunction', 2, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals('success', $return[0]); + }); + $testModel->testFunction('success'); + $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); + } - /** - * @depends testHooking - */ - public function testDataPassing($testModel) { - $that = $this; - Hook::addCallback('TestModel->testFunction', -1, function(&$arguments, $name, &$object, &$function, &$data){ - $data['test'] = 1; - }); - $ids = Hook::addCallback('TestModel->testFunction', 2, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(1, $data['test']); - }); - $testModel->testFunction(true); - $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); - } + /** + * @depends testHooking + */ + public function testArgumentModification($testModel) { + $ids = Hook::addCallback('TestModel->testFunction', -1, function(&$arguments, $name, &$object, &$function, &$data) { + $arguments[0] = 'success'; + }); + $this->assertEquals('success', $testModel->testFunction(true)); + $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); + } - /** - * Do this one last, cause it leaves its callbacks. - * - * @depends testHooking - * @expectedException Exception - * @expectedExceptionMessage Everything is good. - */ - public function testTimeline($testModel) { - $that = $this; - Hook::addCallback('TestModel->testFunction', -1000, function(&$arguments, $name, &$object, &$function, &$data){ - $data['timeline'] = 1; - }); - Hook::addCallback('TestModel->testFunction', -100, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(1, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -90, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(2, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -70, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(3, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -30, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(4, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -10, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(5, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -9, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(6, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -8, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(7, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -7, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(8, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -6, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(9, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -5, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(10, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -4, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(11, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -3, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(12, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -2, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(13, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', -1, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(14, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 1, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(15, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 2, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(16, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 3, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(17, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 4, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(18, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 5, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(19, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 6, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(20, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 7, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(21, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 8, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(22, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 9, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(23, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 10, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(24, $data['timeline']); - $data['timeline']++; - }); - Hook::addCallback('TestModel->testFunction', 1000, function(&$return, $name, &$object, &$function, &$data) use ($that){ - $that->assertEquals(25, $data['timeline']); - // Cool, it all worked. - throw new Exception('Everything is good.'); - }); - $that->assertEquals(27, count(Hook::getCallbacks()['TestModel->testFunction'])); - $testModel->testFunction(true); - } + /** + * @depends testHooking + */ + public function testDataPassing($testModel) { + $that = $this; + Hook::addCallback('TestModel->testFunction', -1, function(&$arguments, $name, &$object, &$function, &$data) { + $data['test'] = 1; + }); + $ids = Hook::addCallback('TestModel->testFunction', 2, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(1, $data['test']); + }); + $testModel->testFunction(true); + $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunction', $ids[0])); + } + + /** + * Do this one last, cause it leaves its callbacks. + * + * @depends testHooking + * @expectedException Exception + * @expectedExceptionMessage Everything is good. + */ + public function testTimeline($testModel) { + $that = $this; + Hook::addCallback('TestModel->testFunction', -1000, function(&$arguments, $name, &$object, &$function, &$data) { + $data['timeline'] = 1; + }); + Hook::addCallback('TestModel->testFunction', -100, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(1, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -90, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(2, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -70, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(3, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -30, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(4, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -10, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(5, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -9, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(6, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -8, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(7, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -7, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(8, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -6, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(9, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -5, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(10, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -4, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(11, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -3, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(12, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -2, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(13, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', -1, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(14, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 1, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(15, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 2, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(16, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 3, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(17, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 4, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(18, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 5, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(19, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 6, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(20, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 7, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(21, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 8, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(22, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 9, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(23, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 10, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(24, $data['timeline']); + $data['timeline']++; + }); + Hook::addCallback('TestModel->testFunction', 1000, function(&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(25, $data['timeline']); + // Cool, it all worked. + throw new Exception('Everything is good.'); + }); + $that->assertEquals(27, count(Hook::getCallbacks()['TestModel->testFunction'])); + $testModel->testFunction(true); + } }