From 0a7b1a62483c774662b3463f57009470407c5692 Mon Sep 17 00:00:00 2001 From: Hunter Perrin Date: Sat, 17 Jun 2017 14:50:26 -0700 Subject: [PATCH 1/3] Added support for variadic functions. Now requires PHP7. --- .gitignore | 3 +- .travis.yml | 7 +- LICENSE | 366 +++++---- composer.json | 12 +- composer.lock | 1470 +++++++++++++++++++++++++++++++++++ src/Hook.php | 523 ++++++------- src/HookOverride.php | 10 +- src/HookOverride_extend.php | 120 +-- testing/TestModel.php | 20 +- testing/bootstrap.php | 22 +- testing/run | 6 +- testing/tests/HookTest.php | 372 ++++----- 12 files changed, 2234 insertions(+), 697 deletions(-) create mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index a056307..0ffc295 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -testing/logs \ No newline at end of file +testing/logs +vendor/ diff --git a/.travis.yml b/.travis.yml index dd2dc35..be5efc0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,8 @@ language: php php: - - 5.4 - - 5.5 - - 5.6 - - hhvm + - 7.0 + - 7.1 + # - hhvm script: ./testing/run diff --git a/LICENSE b/LICENSE index fb6d90b..d645695 100644 --- a/LICENSE +++ b/LICENSE @@ -1,166 +1,202 @@ -GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/composer.json b/composer.json index a7f00bd..7a070f6 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "sciactive/hookphp", "description": "Method hooking in PHP.", - "version": "1.2.2", + "version": "2.0.0", "type": "library", "keywords": [ "method hooking", @@ -9,8 +9,8 @@ "interception" ], "homepage": "http://hookphp.org/", - "time": "2015-04-10", - "license": "LGPL", + "time": "2017-06-17", + "license": "Apache-2.0", "authors": [ { "name": "Hunter Perrin", @@ -19,6 +19,12 @@ "role": "Developer" } ], + "require": { + "php": "~7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, "support": { "issues": "https://github.com/sciactive/hookphp/issues", "wiki": "https://github.com/sciactive/hookphp/wiki", diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..9f3dc51 --- /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" + ], + "hash": "4b2628a6051926652bd0d2ec119de2a8", + "content-hash": "12e6dd1d45d5d71e7006f6010bf3928e", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.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": "2015-06-14 21:17:01" + }, + { + "name": "myclabs/deep-copy", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8e6e04167378abf1ddb4d3522d8755c5fd90d102", + "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-04-12 18:52:22" + }, + { + "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-05 18:14:27" + }, + { + "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-05 17:38:23" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "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": "2015-12-27 11:43:31" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.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": "2016-09-30 07:12:33" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "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": "2016-11-25 06:54:22" + }, + { + "name": "phpspec/prophecy", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "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.6.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-03-02 20:05:34" + }, + { + "name": "phpunit/php-code-coverage", + "version": "5.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "dc421f9ca5082a0c0cb04afb171c765f79add85b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/dc421f9ca5082a0c0cb04afb171c765f79add85b", + "reference": "dc421f9ca5082a0c0cb04afb171c765f79add85b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.0", + "phpunit/php-file-iterator": "^1.3", + "phpunit/php-text-template": "^1.2", + "phpunit/php-token-stream": "^1.4.11 || ^2.0", + "sebastian/code-unit-reverse-lookup": "^1.0", + "sebastian/environment": "^3.0", + "sebastian/version": "^2.0", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "ext-xdebug": "^2.5", + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-xdebug": "^2.5.3" + }, + "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-04-21 08:03:57" + }, + { + "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-03 07:40:28" + }, + { + "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-21 13:50:34" + }, + { + "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-26 11:10:40" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.11", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-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-02-27 10:12:30" + }, + { + "name": "phpunit/phpunit", + "version": "6.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "f2786490399836d2a544a34785c4a8d3ab32cf0e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f2786490399836d2a544a34785c4a8d3ab32cf0e", + "reference": "f2786490399836d2a544a34785c4a8d3ab32cf0e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.3", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.0", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^5.2", + "phpunit/php-file-iterator": "^1.4", + "phpunit/php-text-template": "^1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^4.0", + "sebastian/comparator": "^2.0", + "sebastian/diff": "^1.4.3 || ^2.0", + "sebastian/environment": "^3.0.2", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^1.1 || ^2.0", + "sebastian/object-enumerator": "^3.0.2", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0" + }, + "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.2.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-06-13 14:07:07" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "eabce450df194817a7d7e27e19013569a903a2bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/eabce450df194817a7d7e27e19013569a903a2bf", + "reference": "eabce450df194817a7d7e27e19013569a903a2bf", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^7.0", + "phpunit/php-text-template": "^1.2", + "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-03-03 06:30:20" + }, + { + "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-04 06:30:41" + }, + { + "name": "sebastian/comparator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "20f84f468cb67efee293246e6a09619b891f55f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/20f84f468cb67efee293246e6a09619b891f55f0", + "reference": "20f84f468cb67efee293246e6a09619b891f55f0", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/diff": "^1.2", + "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-03-03 06:26:08" + }, + { + "name": "sebastian/diff", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "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.4-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-05-22 07:24:03" + }, + { + "name": "sebastian/environment", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "02b6b2c7aefe2cdb1185b8dbf8718b0bcedf3ab3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/02b6b2c7aefe2cdb1185b8dbf8718b0bcedf3ab3", + "reference": "02b6b2c7aefe2cdb1185b8dbf8718b0bcedf3ab3", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "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": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2017-05-18 10:10: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-03 13:19:02" + }, + { + "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-27 15:39:26" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/31dd3379d16446c5d86dec32ab1ad1f378581ad8", + "reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.0", + "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-03-12 15:17:29" + }, + { + "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-29 09:07:27" + }, + { + "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-03 06:23:57" + }, + { + "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-28 20:34:47" + }, + { + "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-03 07:35:21" + }, + { + "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-07 12:08:54" + }, + { + "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-23 20:04:58" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "~7.0" + }, + "platform-dev": [] +} diff --git a/src/Hook.php b/src/Hook.php index 0eca341..7d7a578 100644 --- a/src/Hook.php +++ b/src/Hook.php @@ -1,4 +1,6 @@ - * @copyright SciActive.com @@ -15,288 +17,289 @@ */ if (!class_exists('\SciActive\HookOverride')) { - include_once(__DIR__.DIRECTORY_SEPARATOR.'HookOverride.php'); + include_once(__DIR__.DIRECTORY_SEPARATOR.'HookOverride.php'); } class Hook { - /** - * An array of the callbacks for each hook. - * @var array - */ - protected static $hooks = array(); - /** - * A copy of the HookOverride_extend file. - * @var string - */ - private static $hookFile; + /** + * An array of the callbacks for each hook. + * @var array + */ + protected static $hooks = array(); + /** + * A copy of the HookOverride_extend file. + * @var string + */ + private static $hookFile; - /** - * Add a callback. - * - * A callback is called either before a method runs or after. The callback - * is passed an array of arguments or return value which it can freely - * manipulate. If the callback runs before the method and sets the arguments - * array to false (or causes an error), the method will not be run. - * Callbacks before a method are passed the arguments given when the method - * was called, while callbacks after a method are passed the return value - * (in an array) of that method. - * - * The callback can receive up to 5 arguments, in this order: - * - * - &$arguments - An array of either arguments or a return value. - * - $name - The name of the hook. - * - &$object - The object on which the hook caught a method call. - * - &$function - A callback for the method call which was caught. Altering - * this will cause a different function/method to run. - * - &$data - An array in which callbacks can store data to communicate with - * later callbacks. - * - * A hook is the name of whatever method it should catch. A hook can also - * have an arbitrary name, but be wary that it may already exist and it may - * result in your callback being falsely called. In order to reduce the - * chance of this, always use a plus sign (+) and your component's name to - * begin arbitrary hook names. E.g. "+com_games_player_bonus". - * - * If the hook is called explicitly, callbacks defined to run before the - * hook will run immediately followed by callbacks defined to run after. - * - * A negative $order value means the callback will be run before the method, - * while a positive value means it will be run after. The smaller the order - * number, the sooner the callback will be run. You can think of the order - * value as a timeline of callbacks, zero (0) being the actual method being - * hooked. - * - * Additional identical callbacks can be added in order to have a callback - * called multiple times for one hook. - * - * The hook "all" is a pseudo hook which will run regardless of what was - * actually caught. Callbacks attached to the "all" hook will run before - * callbacks attached to the actual hook. - * - * Note: Be careful to avoid recursive callbacks, as they may result in an - * infinite loop. All methods under $_ are automatically hooked. - * - * @param string $hook The name of the hook to catch. - * @param int $order The order can be negative, which will run before the method, or positive, which will run after the method. It cannot be zero. - * @param callback The callback. - * @return array An array containing the IDs of the new callback and all matching callbacks. - * @uses \SciActive\Hook::sortCallbacks() To resort the callback array in the correct order. - */ - public static function addCallback($hook, $order, $function) { - $callback = array($order, $function); - if (!isset(Hook::$hooks[$hook])) { - Hook::$hooks[$hook] = array(); - } - Hook::$hooks[$hook][] = $callback; - uasort(Hook::$hooks[$hook], '\\SciActive\\Hook::sortCallbacks'); - return array_keys(Hook::$hooks[$hook], $callback); + /** + * Add a callback. + * + * A callback is called either before a method runs or after. The callback + * is passed an array of arguments or return value which it can freely + * manipulate. If the callback runs before the method and sets the arguments + * array to false (or causes an error), the method will not be run. + * Callbacks before a method are passed the arguments given when the method + * was called, while callbacks after a method are passed the return value + * (in an array) of that method. + * + * The callback can receive up to 5 arguments, in this order: + * + * - &$arguments - An array of either arguments or a return value. + * - $name - The name of the hook. + * - &$object - The object on which the hook caught a method call. + * - &$function - A callback for the method call which was caught. Altering + * this will cause a different function/method to run. + * - &$data - An array in which callbacks can store data to communicate with + * later callbacks. + * + * A hook is the name of whatever method it should catch. A hook can also + * have an arbitrary name, but be wary that it may already exist and it may + * result in your callback being falsely called. In order to reduce the + * chance of this, always use a plus sign (+) and your component's name to + * begin arbitrary hook names. E.g. "+com_games_player_bonus". + * + * If the hook is called explicitly, callbacks defined to run before the + * hook will run immediately followed by callbacks defined to run after. + * + * A negative $order value means the callback will be run before the method, + * while a positive value means it will be run after. The smaller the order + * number, the sooner the callback will be run. You can think of the order + * value as a timeline of callbacks, zero (0) being the actual method being + * hooked. + * + * Additional identical callbacks can be added in order to have a callback + * called multiple times for one hook. + * + * The hook "all" is a pseudo hook which will run regardless of what was + * actually caught. Callbacks attached to the "all" hook will run before + * callbacks attached to the actual hook. + * + * Note: Be careful to avoid recursive callbacks, as they may result in an + * infinite loop. All methods under $_ are automatically hooked. + * + * @param string $hook The name of the hook to catch. + * @param int $order The order can be negative, which will run before the method, or positive, which will run after the method. It cannot be zero. + * @param callback The callback. + * @return array An array containing the IDs of the new callback and all matching callbacks. + * @uses \SciActive\Hook::sortCallbacks() To resort the callback array in the correct order. + */ + public static function addCallback($hook, $order, $function) { + $callback = array($order, $function); + if (!isset(Hook::$hooks[$hook])) { + Hook::$hooks[$hook] = array(); } + Hook::$hooks[$hook][] = $callback; + uasort(Hook::$hooks[$hook], '\\SciActive\\Hook::sortCallbacks'); + return array_keys(Hook::$hooks[$hook], $callback); + } - /** - * Delete a callback by its ID. - * - * @param string $hook The name of the callback's hook. - * @param int $id The ID of the callback. - * @return int 1 if the callback was deleted, 2 if it didn't exist. - */ - public static function delCallbackByID($hook, $id) { - if (!isset(Hook::$hooks[$hook][$id])) { - return 2; - } - unset(Hook::$hooks[$hook][$id]); - return 1; + /** + * Delete a callback by its ID. + * + * @param string $hook The name of the callback's hook. + * @param int $id The ID of the callback. + * @return int 1 if the callback was deleted, 2 if it didn't exist. + */ + public static function delCallbackByID($hook, $id) { + if (!isset(Hook::$hooks[$hook][$id])) { + return 2; } + unset(Hook::$hooks[$hook][$id]); + return 1; + } - /** - * Get the array of callbacks. - * - * Callbacks are stored in arrays inside this array. The keys of this array - * are the name of the hook whose callbacks are contained in its value as an - * array. Each array contains the values $order, $function, in that order. - * - * @return array An array of callbacks. - */ - public static function getCallbacks() { - return Hook::$hooks; - } + /** + * Get the array of callbacks. + * + * Callbacks are stored in arrays inside this array. The keys of this array + * are the name of the hook whose callbacks are contained in its value as an + * array. Each array contains the values $order, $function, in that order. + * + * @return array An array of callbacks. + */ + public static function getCallbacks() { + return Hook::$hooks; + } - /** - * 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; - } + /** + * 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->isVariadic() ? '...' : ''; + $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 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; } + 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..b9e0a39 100644 --- a/src/HookOverride.php +++ b/src/HookOverride.php @@ -1,8 +1,10 @@ - * @copyright SciActive.com @@ -12,4 +14,6 @@ /** * A base class to check whether an object has been hooked. */ -class HookOverride { } \ No newline at end of file +class HookOverride { + +} diff --git a/src/HookOverride_extend.php b/src/HookOverride_extend.php index a002d3a..116b0d0 100644 --- a/src/HookOverride_extend.php +++ b/src/HookOverride_extend.php @@ -1,8 +1,10 @@ - * @copyright SciActive.com @@ -16,76 +18,76 @@ * hooking. */ class HookOverride__NAMEHERE_ extends HookOverride implements \JsonSerializable { - /** - * Used to store the overridden class. - * @var mixed $_hookObject - */ - protected $_hookObject = null; - /** - * Used to store the prefix (the object's variable name). - * @var string $_hookPrefix - */ - protected $_hookPrefix = ''; + /** + * Used to store the overridden class. + * @var mixed $_hookObject + */ + protected $_hookObject = null; + /** + * Used to store the prefix (the object's variable name). + * @var string $_hookPrefix + */ + protected $_hookPrefix = ''; - public function _hookObject() { - return $this->_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..628f6a5 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 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 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 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 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 testVariadic($testModel) { + $that = $this; + $ids = Hook::addCallback('TestModel->testFunctionVariadic', 2, function (&$return, $name, &$object, &$function, &$data) use ($that) { + $that->assertEquals(['success', [1, 2, 3]], $return[0]); + }); + $testModel->testFunction('success', 1, 2, 3); + $this->assertEquals(1, Hook::delCallbackByID('TestModel->testFunctionVariadic', $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); + } } From fc15a05c5e06362f28bc5fc6e3cfb54a73e88b41 Mon Sep 17 00:00:00 2001 From: Hunter Perrin Date: Sat, 17 Jun 2017 14:55:51 -0700 Subject: [PATCH 2/3] Updated readme. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4de7f58..91d4994 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# logo HookPHP +# HookPHP -[![Build Status](https://scrutinizer-ci.com/g/sciactive/hookphp/badges/build.png?b=master)](https://scrutinizer-ci.com/g/sciactive/hookphp/build-status/master) [![Latest Stable Version](https://img.shields.io/packagist/v/sciactive/hookphp.svg?style=flat)](https://packagist.org/packages/sciactive/hookphp) [![License](https://img.shields.io/packagist/l/sciactive/hookphp.svg?style=flat)](https://packagist.org/packages/sciactive/hookphp) [![Open Issues](https://img.shields.io/github/issues/sciactive/hookphp.svg?style=flat)](https://github.com/sciactive/hookphp/issues) [![Code Quality](https://img.shields.io/scrutinizer/g/sciactive/hookphp.svg?style=flat)](https://scrutinizer-ci.com/g/sciactive/hookphp/) [![Coverage](https://img.shields.io/scrutinizer/coverage/g/sciactive/hookphp.svg?style=flat)](https://scrutinizer-ci.com/g/sciactive/hookphp/) +[![Build Status](https://img.shields.io/travis/sciactive/hookphp.svg)](https://travis-ci.org/sciactive/hookphp) [![Latest Stable Version](https://img.shields.io/packagist/v/sciactive/hookphp.svg?style=flat)](https://packagist.org/packages/sciactive/hookphp) [![License](https://img.shields.io/packagist/l/sciactive/hookphp.svg?style=flat)](https://packagist.org/packages/sciactive/hookphp) [![Open Issues](https://img.shields.io/github/issues/sciactive/hookphp.svg?style=flat)](https://github.com/sciactive/hookphp/issues) [![Code Quality](https://img.shields.io/scrutinizer/g/sciactive/hookphp.svg?style=flat)](https://scrutinizer-ci.com/g/sciactive/hookphp/) [![Coverage](https://img.shields.io/scrutinizer/coverage/g/sciactive/hookphp.svg?style=flat)](https://scrutinizer-ci.com/g/sciactive/hookphp/) -Method hooking in PHP. +Method hooking (decorators) in PHP. ## Installation From f0605a702ee42eeb1d58220c1ad900e47a0b37cb Mon Sep 17 00:00:00 2001 From: Hunter Perrin Date: Sat, 17 Jun 2017 14:59:58 -0700 Subject: [PATCH 3/3] Adding composer install to Travis config. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index be5efc0..5a6d2c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,6 @@ php: - 7.1 # - hhvm +install: composer install --no-interaction + script: ./testing/run