From 21861db36e208a12036a396bf14e2902a27728bd Mon Sep 17 00:00:00 2001 From: eeliu Date: Fri, 3 Jul 2020 16:27:14 +0800 Subject: [PATCH] migrate to naver repo --- .gitignore | 9 + .travis.yml | 13 + Changes.md | 37 ++ LICENSE | 201 +++++++ PHPUnit.xml | 22 + Readme.md | 108 ++++ auto_pinpointed.php | 21 + composer.json | 24 + lib/pinpoint/Common/AopClassMap.php | 53 ++ lib/pinpoint/Common/ClassFile.php | 123 +++++ lib/pinpoint/Common/CodeVisitor.php | 171 ++++++ .../Common/GenOriginClassFileHelper.php | 510 ++++++++++++++++++ .../Common/GenProxiedClassFileHelper.php | 182 +++++++ .../Common/GenRequiredBIFileHelper.php | 347 ++++++++++++ lib/pinpoint/Common/GenerateBIHelper.php | 101 ++++ lib/pinpoint/Common/OrgClassParse.php | 142 +++++ lib/pinpoint/Common/PinpointClassLoader.php | 84 +++ lib/pinpoint/Common/PinpointDriver.php | 101 ++++ lib/pinpoint/Common/PluginParser.php | 133 +++++ lib/pinpoint/Common/PluginVisitor.php | 89 +++ lib/pinpoint/Common/Util.php | 105 ++++ lib/pinpoint/Common/WrapperInternalClass.php | 55 ++ lib/pinpoint/test/ClassParseTest.php | 90 ++++ .../pinpoint/test/Proxied_TestClass.php | 80 +++ .../pinpoint/test/Proxied_TestTrait.php | 19 + .../Comparison/pinpoint/test/TestClass.php | 142 +++++ .../pinpoint/test/TestClass_required.php | 36 ++ .../Comparison/pinpoint/test/TestTrait.php | 24 + .../pinpoint/test/TestTrait_required.php | 3 + lib/pinpoint/test/GenBiClassTest.php | 55 ++ lib/pinpoint/test/PluginParserTest.php | 49 ++ lib/pinpoint/test/TestClass.php | 80 +++ lib/pinpoint/test/TestTrait.php | 19 + lib/pinpoint/test/UtilTest.php | 44 ++ lib/pinpoint/test/bootstrap.php | 2 + 35 files changed, 3274 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 Changes.md create mode 100644 LICENSE create mode 100644 PHPUnit.xml create mode 100644 Readme.md create mode 100644 auto_pinpointed.php create mode 100644 composer.json create mode 100644 lib/pinpoint/Common/AopClassMap.php create mode 100644 lib/pinpoint/Common/ClassFile.php create mode 100644 lib/pinpoint/Common/CodeVisitor.php create mode 100644 lib/pinpoint/Common/GenOriginClassFileHelper.php create mode 100644 lib/pinpoint/Common/GenProxiedClassFileHelper.php create mode 100644 lib/pinpoint/Common/GenRequiredBIFileHelper.php create mode 100644 lib/pinpoint/Common/GenerateBIHelper.php create mode 100644 lib/pinpoint/Common/OrgClassParse.php create mode 100644 lib/pinpoint/Common/PinpointClassLoader.php create mode 100644 lib/pinpoint/Common/PinpointDriver.php create mode 100644 lib/pinpoint/Common/PluginParser.php create mode 100644 lib/pinpoint/Common/PluginVisitor.php create mode 100644 lib/pinpoint/Common/Util.php create mode 100644 lib/pinpoint/Common/WrapperInternalClass.php create mode 100644 lib/pinpoint/test/ClassParseTest.php create mode 100644 lib/pinpoint/test/Comparison/pinpoint/test/Proxied_TestClass.php create mode 100644 lib/pinpoint/test/Comparison/pinpoint/test/Proxied_TestTrait.php create mode 100644 lib/pinpoint/test/Comparison/pinpoint/test/TestClass.php create mode 100644 lib/pinpoint/test/Comparison/pinpoint/test/TestClass_required.php create mode 100644 lib/pinpoint/test/Comparison/pinpoint/test/TestTrait.php create mode 100644 lib/pinpoint/test/Comparison/pinpoint/test/TestTrait_required.php create mode 100644 lib/pinpoint/test/GenBiClassTest.php create mode 100644 lib/pinpoint/test/PluginParserTest.php create mode 100644 lib/pinpoint/test/TestClass.php create mode 100644 lib/pinpoint/test/TestTrait.php create mode 100644 lib/pinpoint/test/UtilTest.php create mode 100644 lib/pinpoint/test/bootstrap.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..587a064 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +composer.phar +/vendor/ +.idea/ +composer.lock +lib/pinpoint/test/Cache + +# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control +# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file +# composer.lock diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2a75e4e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: php + +php: + - 7.1 + - 7.2 + - 7.3 + - 7.4 + +install: +- travis_retry composer install --no-interaction --no-suggest + +script: +- vendor/bin/phpunit --configuration PHPUnit.xml --testsuit pinpoint --testdox \ No newline at end of file diff --git a/Changes.md b/Changes.md new file mode 100644 index 0000000..b6e061b --- /dev/null +++ b/Changes.md @@ -0,0 +1,37 @@ +## Changes + +### v0.2.4 Support references in parameters +1. Support pinpoint_get_func_ref_args +2. Add debug_backtrac when pinpoint_get_func_ref_args not find +3. Support PHP 7.4 + +### 0.2.3 Support user filter + +1. User can filter plugins related class loader by extending `Pinpoint\Common\AopClassMap`. + +``` php +namespace Plugins; +use pinpoint\Common\AopClassMap; + +class ClassMapInFile extends AopClassMap +{ + public function findFile($classFullName) + { + $file = parent::findFile($classFullName); + if($file){ + if (some condition not allow) + { + reject reload this file from "__DIR__.'/Cache/'",use the origin file + return null; + }else{ + return $file; + } + } + return $file; + } +} + +``` + +2020/3/19 +1. Add user defined class loader ( Currently try to support yii) \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..db74914 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + 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 2020-present NAVER Corp. + + 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/PHPUnit.xml b/PHPUnit.xml new file mode 100644 index 0000000..1d6fe94 --- /dev/null +++ b/PHPUnit.xml @@ -0,0 +1,22 @@ + + + + + lib/pinpoint/test + + + + + lib/pinpoint/Common + + + \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..87a3ecb --- /dev/null +++ b/Readme.md @@ -0,0 +1,108 @@ +[![Build Status](https://travis-ci.com/eeliu/php_simple_aop.svg?branch=master)](https://travis-ci.com/eeliu/php_simple_aop) + +## How to Use + +### Import from packagist + +Add requirement into composer.json + +```Json + "require": { + "naver/php_simple_aop": "v1.0.0" + } +``` + +> Latest +PHP7: `v1.0.0` + +### Write your plugins +This is a plugin template for reference. + +```php +/// Placing "///@hook:" here: aop on function(method) on before,end and Exception +///@hook:app\AppDate::output +class CommonPlugin +{ + //$apId: The function(method) name + //$who: If watching a method, $who is that instance + //$args: array parameters $argv = $args[0] + public function __construct($apId,$who,&...$args){ + // $this->argv = $args[0]; + // $this->funName =$apId; + // $this->instance = $who; + } + // watching before + ///@hook:app\DBcontrol::connectDb + public function onBefore(){ + + } + + // watching after + ///@hook:app\DBcontrol::getData1 app\DBcontrol::\array_push + public function onEnd(&$ret){ + + } + + // Exception + ///@hook:app\DBcontrol::getData2 + public function onException($e){ + } +} +``` + +> Example + +https://github.com/naver/pinpoint-c-agent/tree/v0.2.2/PHP/pinpoint_php_example/Plugins + +### Activate plugins +This could be found in PHP/pinpoint_php_example/app/index.php. + +``` php + If you found a bug, please create an issue to us without any hesitate. + +> If it could help you, please give us a star as a support! Thanks! + +## Copyright + +``` +Copyright 2020-present NAVER Corp. + +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/auto_pinpointed.php b/auto_pinpointed.php new file mode 100644 index 0000000..079e47d --- /dev/null +++ b/auto_pinpointed.php @@ -0,0 +1,21 @@ +init($classMap); + +if(class_exists("\Plugins\PerRequestPlugins")){ + \Plugins\PerRequestPlugins::instance(); +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..6ecbedc --- /dev/null +++ b/composer.json @@ -0,0 +1,24 @@ +{ + "name": "eeliu/php_simple_aop", + "description": "A simple Aop library via php-parse", + "type": "library", + "license": "BSD-3-Clause", + "authors": [ + { + "name": "eeliu", + "email": "eeliu2009@gmail.com" + } + ], + "autoload": { + "psr-4": { + "pinpoint\\": "lib/pinpoint/" + } + }, + "minimum-stability": "dev", + "require-dev": { + "phpunit/phpunit": "^7" + }, + "require": { + "nikic/php-parser": "^4.1" + } +} diff --git a/lib/pinpoint/Common/AopClassMap.php b/lib/pinpoint/Common/AopClassMap.php new file mode 100644 index 0000000..ed10e76 --- /dev/null +++ b/lib/pinpoint/Common/AopClassMap.php @@ -0,0 +1,53 @@ +index_file_path) ) + { + $this->classLoaderMap = unserialize(file_get_contents($this->index_file_path)); + $this->cached = true; + return false; + }else{ + return true; + } + } + + public function persistenceClassMapping() + { + if(!$this->cached){ + $context = serialize($this->classLoaderMap); + Util::flushStr2File($context,$this->index_file_path); + } + } + + public function findFile($classFullName) + { + if(isset($this->classLoaderMap[$classFullName])) + { + return $this->classLoaderMap[$classFullName]; + } + return null; + } + + public function insertMapping($cl,$file) + { + $this->classLoaderMap[$cl] = $file; + } + +} \ No newline at end of file diff --git a/lib/pinpoint/Common/ClassFile.php b/lib/pinpoint/Common/ClassFile.php new file mode 100644 index 0000000..50548fb --- /dev/null +++ b/lib/pinpoint/Common/ClassFile.php @@ -0,0 +1,123 @@ +prefix = $prefix; + } + + public function getNode() + { + return $this->node; + } + + public function handleEnterNamespaceNode(&$node) + { + assert($node instanceof Node\Stmt\Namespace_); + $this->namespace = trim($node->name->toString()); + } + + public function handleEnterClassNode(&$node) + { + assert($node instanceof Node\Stmt\Class_); + $this->className = trim($this->namespace.'\\'.$node->name->toString()); + } + + public function handleEnterTraitNode(&$node) + { + assert($node instanceof Node\Stmt\Trait_); + // $this->traitName = Foo trait Foo{} + $this->traitName = trim($this->namespace.'\\'.$node->name->toString()); + } + + public function handleClassEnterMethodNode(&$node) + { + assert($node instanceof Node\Stmt\ClassMethod); + $this->funcName = $node->name->toString(); + $this->classMethod =$this->className.'::'.$this->funcName; + $this->hasRet = false; + } + + abstract function handleLeaveMethodNode(&$node,&$info); + + public function markHasReturn(&$node) + { + if(isset($node->expr)) + { + $this->hasRet = true; + } + } + + public function markHasYield(&$node) + { + $this->hasRet = true; + } + + + abstract function handleAfterTravers(&$nodes,&$mFuncAr); + abstract function handleLeaveNamespace(&$nodes); + abstract function handlerUseNode(&$nodes); +} diff --git a/lib/pinpoint/Common/CodeVisitor.php b/lib/pinpoint/Common/CodeVisitor.php new file mode 100644 index 0000000..c607a86 --- /dev/null +++ b/lib/pinpoint/Common/CodeVisitor.php @@ -0,0 +1,171 @@ +ospIns = $ospIns; + $this->curClass = $ospIns->className; + } + + public function enterNode(Node $node) + { + if($node instanceof Node\Stmt\Namespace_) + { + $this->curNamespace = $node->name->toString(); + /// set namespace + $this->ospIns->originClassFile->handleEnterNamespaceNode($node); + $this->ospIns->proxiedClassFile->handleEnterNamespaceNode($node); + + $reqFile = new GenRequiredBIFileHelper($this->curNamespace); + foreach ($this->ospIns->mFuncAr as $key => $value) + { + $ret = Util::isBuiltIn($key); + + if($ret == Util::U_Method){ + list($clName,$clMethod) = preg_split ("/[::|\\\]/",$key,-1,PREG_SPLIT_NO_EMPTY); + $this->builtInAr[] = $clName; + $reqFile->extendsMethod($clName,$clMethod,$value); + }elseif ($ret == Util::U_Function){ + + list($funcName) = preg_split ("/[\\\]/",$key,-1,PREG_SPLIT_NO_EMPTY); + $this->builtInAr [] = $funcName ; + $reqFile->extendsFunc($funcName,$value); + }else{ + //do nothing + } + } + + $reqRelativityFile = str_replace('\\','/', $this->curClass).'_required.php'; + $reqFile->loadToFile(AOP_CACHE_DIR.$reqRelativityFile); + $this->ospIns->requiredFile = AOP_CACHE_DIR.$reqRelativityFile; + $this->ospIns->proxiedClassFile->addRequiredFile($reqRelativityFile); + } + elseif ($node instanceof Node\Stmt\Use_){ + $this->ospIns->proxiedClassFile->handlerUseNode($node); + $this->ospIns->originClassFile->handlerUseNode($node); + } + elseif ($node instanceof Node\Stmt\Class_){ + + $this->ospIns->originClassFile->handleEnterClassNode($node); + $this->ospIns->proxiedClassFile->handleEnterClassNode($node); + } + elseif( $node instanceof Node\Stmt\Trait_){ + if( $this->curNamespace.'\\'.$node->name->toString() != $this->curClass) + { + // ignore uncared + return NodeTraverser::DONT_TRAVERSE_CHILDREN; + } + + $this->ospIns->proxiedClassFile->handleEnterTraitNode($node); + $this->ospIns->originClassFile->handleEnterTraitNode($node); + }elseif ($node instanceof Node\Stmt\ClassMethod) + { + $this->ospIns->originClassFile->handleClassEnterMethodNode($node); + $this->ospIns->proxiedClassFile->handleClassEnterMethodNode($node); + } + elseif ( $node instanceof Node\Stmt\Return_) + { + $this->ospIns->originClassFile->markHasReturn($node); + } + elseif ($node instanceof Node\Expr\Yield_){ + $this->ospIns->originClassFile->markHasYield($node); + } + } + + + public function leaveNode(Node $node) + { + if ($node instanceof Node\Stmt\ClassMethod){ + $func = trim( $node->name->toString()); + if(array_key_exists($func,$this->ospIns->mFuncAr)) + { + $this->ospIns->originClassFile->handleLeaveMethodNode($node,$this->ospIns->mFuncAr[$func]); + $this->ospIns->proxiedClassFile->handleLeaveMethodNode($node,$this->ospIns->mFuncAr[$func]); + /// remove the func + unset( $this->ospIns->mFuncAr[$func] ); + } + }elseif ($node instanceof Node\Name\FullyQualified){ + // use Foo\Name replace \Name + $name = $node->toString(); + if(! in_array($name,$this->builtInAr) ){ + return $node; + } + return $this->ospIns->proxiedClassFile->handleFullyQualifiedNode($node); + } + elseif ($node instanceof Node\Scalar\MagicConst){ + + $this->ospIns->proxiedClassFile->handleMagicConstNode($node); + }elseif ($node instanceof Node\Stmt\Namespace_){ + return $this->ospIns->proxiedClassFile->handleLeaveNamespace($node); + } + elseif ($node instanceof Node\Stmt\Class_){ + + $this->ospIns->proxiedClassFile->handleLeaveClassNode($node); + + }elseif ($node instanceof Node\Stmt\Trait_){ + + $this->ospIns->proxiedClassFile->handleLeaveTraitNode($node); + } + elseif ($node instanceof Node\Stmt\UseUse){ + /// scene : use \PDO + /// replace \PDO to \Np\PDO + if( in_array($node->name->toString(),$this->builtInAr)) + { + $node->name = new Node\Name($this->curNamespace.'\\'.$node->name->toString()); + } + return $node; + } + } + + public function afterTraverse(array $nodes) + { + $node = $this->ospIns->proxiedClassFile->handleAfterTravers($nodes, + $this->ospIns->mFuncAr); + + $this->ospIns->orgClassNodeDoneCB($node,$this->ospIns->proxiedClassFile->name); + + $node = $this->ospIns->originClassFile->handleAfterTravers($nodes, + $this->ospIns->mFuncAr); + + $this->ospIns->shadowClassNodeDoneCB($node,$this->ospIns->originClassFile->fileName); + + } + +} diff --git a/lib/pinpoint/Common/GenOriginClassFileHelper.php b/lib/pinpoint/Common/GenOriginClassFileHelper.php new file mode 100644 index 0000000..6629d6f --- /dev/null +++ b/lib/pinpoint/Common/GenOriginClassFileHelper.php @@ -0,0 +1,510 @@ +factory= new BuilderFactory(); + + $this->classNode = null; + $this->traitNode = null; + } + + + public function handleEnterNamespaceNode(&$node) + { + parent::handleEnterNamespaceNode($node); + + } + + public function handleEnterClassNode(&$node) + { + assert($node instanceof Node\Stmt\Class_); + parent::handleEnterClassNode($node); + + $extendClass = $this->prefix.$node->name->toString(); + $this->classNode = $this->factory->class(trim($node->name->toString()))->extend($extendClass); + $this->useBlockAr[$this->namespace.'\\'.$extendClass] = null; + + switch($node->flags) { + case Node\Stmt\Class_::MODIFIER_FINAL: + $this->classNode->makeFinal(); + break; + case Node\Stmt\Class_::MODIFIER_ABSTRACT: + $this->classNode->makeAbstract(); + break; + default: + break; + } + + $this->handleMethodNodeLeaveFunc = 'handleClassLeaveMethodNode'; + $this->handleEndTraversFunc = 'handleAfterTraversClass'; + } + + public function handleEnterTraitNode(&$node) + { + assert($node instanceof Node\Stmt\Trait_); + parent::handleEnterTraitNode($node); + $this->traitNode = $this->factory->trait(trim($node->name->toString())); + $this->extendTraitName = $this->prefix.$node->name->toString(); + $this->handleMethodNodeLeaveFunc = 'handleTraitLeaveMethodNode'; + $this->handleEndTraversFunc = 'handleAfterTraversTrait'; + } + + public static function convertParamsName2Arg($params) + { + assert(is_array($params)); + + $args = []; + + foreach ($params as $param) + { + assert($param instanceof Node\Param); + $args [] = new Node\Arg($param->var); + } + + return $args; + } + + + public function handleClassLeaveMethodNode(&$node,&$info) + { + /// todo this func looks ugly + + assert($node instanceof Node\Stmt\ClassMethod); + + list($mode, $namespace, $className) = $info; + + $np = $namespace . '\\' . $className; + + if(!in_array($np,$this->useBlockAr)){ + $this->useBlockAr[$np] =null; + } + + // foo_1 + $thisFuncName = $node->name->toString(); + + $funcVar = new Node\Arg(new Node\Scalar\MagicConst\Method()); + + // public function funcName(){} + $thisMethod = $this->factory->method($thisFuncName); + + if ($node->flags & Node\Stmt\Class_::MODIFIER_PUBLIC) { + $thisMethod->makePublic(); + } + + if ($node->flags & Node\Stmt\Class_::MODIFIER_PRIVATE) { + $thisMethod->makeProtected(); + } + + if ($node->flags & Node\Stmt\Class_::MODIFIER_ABSTRACT) { + + $thisMethod->makeAbstract(); + } + + if($node->flags & Node\Stmt\Class_::MODIFIER_FINAL){ + $thisMethod->makeFinal(); + } + + if ($node->flags & Node\Stmt\Class_::MODIFIER_PROTECTED) { + $thisMethod->makeProtected(); + } + + if ($node->flags & Node\Stmt\Class_::MODIFIER_STATIC) { + $thisMethod->makeStatic(); + $selfVar = new Node\Arg(new Node\Expr\ConstFetch(new Node\Name('null'))); + }else{ + $selfVar = new Node\Arg(new Node\Expr\Variable('this')); + } + + $pluginArgs = array_merge([$funcVar,$selfVar],GenOriginClassFileHelper::convertParamsName2Arg($node->params)); + + $thisMethod->addParams($node->params); + if($node->returnType){ + $thisMethod->setReturnType($node->returnType); + } + + $varName = $className.'_'.$thisFuncName.'_var'; + $retName = $className.'_'.$thisFuncName.'_ret'; + + /// $var = new CommonPlugins(__FUNCTION__,self,$p); + $newPluginsStm = new Node\Stmt\Expression(new Node\Expr\Assign(new Node\Expr\Variable($varName), + $this->factory->new($className, $pluginArgs))); + + $thisMethod->addStmt($newPluginsStm); + // $var = null; + $newVar = new Node\Stmt\Expression(new Node\Expr\Assign(new Node\Expr\Variable($retName), + new Node\Expr\ConstFetch(new Node\Name('null')))); + $thisMethod->addStmt($newVar); + + $tryBlock = []; + $catchNode = []; + + if ($mode & PluginParser::BEFORE) + { + // $var->onBefore(); + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall(new Node\Expr\Variable($varName), "onBefore")); + } + + if ($this->hasRet) { + /// $ret = paraent::$thisFuncName(); + $tryBlock[] = new Node\Stmt\Expression(new Node\Expr\Assign( + new Node\Expr\Variable($retName), + new Node\Expr\StaticCall(new Node\Name("parent"), + new Node\Identifier($thisFuncName), + GenOriginClassFileHelper::convertParamsName2Arg($node->params)))); + + /// $var->onEnd($ret); + if($mode & PluginParser::END) + { + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall( + new Node\Expr\Variable($varName), + "onEnd", + [new Node\Expr\Variable($retName)] + ) + ); + } + + /// return $var; + $tryBlock[] = new Node\Stmt\Return_(new Node\Expr\Variable($retName)); + + } else { + /// paraent::$thisFuncName(); + + $tryBlock[] = new Node\Stmt\Expression($this->factory->staticCall( + new Node\Name("parent") + , new Node\Identifier($thisFuncName), + GenOriginClassFileHelper::convertParamsName2Arg($node->params))); + + /// $var->onEnd($ret); + if($mode & PluginParser::END) + { + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall( + new Node\Expr\Variable($varName), + "onEnd", + [new Node\Expr\Variable($retName)] + ) + ); + } + } + + $expArgs = []; + $expArgs[] = new Node\Arg(new Node\Expr\Variable('e')) ; + + if ($mode & PluginParser::EXCEPTION) { + + $catchBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall(new Node\Expr\Variable($varName), + "onException",$expArgs)); + + } + + $catchBlock[] = new Node\Stmt\Throw_(new Node\Expr\Variable("e")); + + $catchNode[] = new Node\Stmt\Catch_([new Node\Name('\Exception')], + new Node\Expr\Variable('e'), + $catchBlock); + + $tryCatchFinallyNode = new Node\Stmt\TryCatch($tryBlock,$catchNode); + + $thisMethod->addStmt($tryCatchFinallyNode); + + $this->classNode->addStmt($thisMethod); + } + + public function handleTraitLeaveMethodNode(&$node,&$info) + { + /// todo this func looks ugly + + /// - check use , add use Proxied_Foo { } + /// - insert alias use Proxied_Foo::xxx as Foo_xxxx + /// - new function xxxx + + assert($node instanceof Node\Stmt\ClassMethod); + + list($mode, $namespace, $className) = $info; + + // foo_1 + $thisFuncName = $node->name->toString(); + + $np = $namespace . '\\' . $className; + // use CommonPlugins\Plugins; + if(!in_array($np,$this->useBlockAr)){ + $this->useBlockAr[$np] = null; + } + + // $this->extendTraitName::$thisFuncName as $this->extendTraitName_$thisFuncName; + $this->trailUseAsArray[] = $thisFuncName; + $extendMethodName = $this->extendTraitName.'_'.$thisFuncName; + + + $funcVar = new Node\Arg(new Node\Scalar\MagicConst\Method()); + + // public function funcName(){} + $thisMethod = $this->factory->method($thisFuncName); + + if ($node->flags & Node\Stmt\Class_::MODIFIER_PUBLIC) { + $thisMethod->makePublic(); + } + + if ($node->flags & Node\Stmt\Class_::MODIFIER_PRIVATE) { + $thisMethod->makePrivate(); + } + + if ($node->flags & Node\Stmt\Class_::MODIFIER_ABSTRACT) { + + $thisMethod->makeAbstract(); + } + + if($node->flags & Node\Stmt\Class_::MODIFIER_FINAL){ + $thisMethod->makeFinal(); + } + + if ($node->flags & Node\Stmt\Class_::MODIFIER_PROTECTED) { + $thisMethod->makeProtected(); + } + + if ($node->flags & Node\Stmt\Class_::MODIFIER_STATIC) { + $thisMethod->makeStatic(); + $selfVar = new Node\Arg(new Node\Expr\ConstFetch(new Node\Name('null'))); + }else{ + $selfVar = new Node\Arg(new Node\Expr\Variable('this')); + } + + $pluginArgs = array_merge([$funcVar,$selfVar],GenOriginClassFileHelper::convertParamsName2Arg($node->params)); + + $thisMethod->addParams($node->params); + if($node->returnType){ + $thisMethod->setReturnType($node->returnType); + } + + $varName = $className.'_'.$thisFuncName.'_var'; + $retName = $className.'_'.$thisFuncName.'_ret'; + + /// $var = new CommonPlugins(__FUNCTION__,self,$p); + $newPluginsStm = new Node\Stmt\Expression(new Node\Expr\Assign(new Node\Expr\Variable($varName), + $this->factory->new($className, $pluginArgs))); + + $thisMethod->addStmt($newPluginsStm); + // $var = null; + $newVar = new Node\Stmt\Expression(new Node\Expr\Assign(new Node\Expr\Variable($retName), + new Node\Expr\ConstFetch(new Node\Name('null')))); + $thisMethod->addStmt($newVar); + + $tryBlock = []; + $catchNode = []; + + if ($mode & PluginParser::BEFORE) + { + // $var->onBefore(); + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall(new Node\Expr\Variable($varName), "onBefore")); + } + + if ($this->hasRet) { + /// $ret = $this->Proxied_xxx(&...$args); + $tryBlock[] = new Node\Stmt\Expression(new Node\Expr\Assign( + new Node\Expr\Variable($retName), + new Node\Expr\MethodCall(new Node\Expr\Variable("this"), + new Node\Identifier($extendMethodName), + GenOriginClassFileHelper::convertParamsName2Arg($node->params)))); + + /// $var->onEnd($ret); + if($mode & PluginParser::END) + { + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall( + new Node\Expr\Variable($varName), + "onEnd", + [new Node\Expr\Variable($retName)] + ) + ); + } + + /// return $var; + $tryBlock[] = new Node\Stmt\Return_(new Node\Expr\Variable($retName)); + + } else { + /// $this->>$thisFuncName(); + $tryBlock[] = new Node\Stmt\Expression( new Node\Expr\MethodCall(new Node\Expr\Variable("this"), + new Node\Identifier($extendMethodName), + GenOriginClassFileHelper::convertParamsName2Arg($node->params))); + + /// $var->onEnd($ret); + if($mode & PluginParser::END) + { + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall( + new Node\Expr\Variable($varName), + "onEnd", + [new Node\Expr\Variable($retName)] + ) + ); + } + } + + $expArgs = []; + $expArgs[] = new Node\Arg(new Node\Expr\Variable('e')) ; + + if ($mode & PluginParser::EXCEPTION) { + + $catchBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall(new Node\Expr\Variable($varName), + "onException",$expArgs)); + + } + + $catchBlock[] = new Node\Stmt\Throw_(new Node\Expr\Variable("e")); + + $catchNode[] = new Node\Stmt\Catch_([new Node\Name('\Exception')], + new Node\Expr\Variable('e'), + $catchBlock); + + $tryCatchFinallyNode = new Node\Stmt\TryCatch($tryBlock,$catchNode); + + $thisMethod->addStmt($tryCatchFinallyNode); + + $this->traitNode->addStmt($thisMethod); + + } + + public function handleLeaveMethodNode(&$node,&$info) + { + call_user_func_array([$this,$this->handleMethodNodeLeaveFunc],[&$node,&$info]); + } + + + + + public function handleAfterTraversClass(&$nodes,&$mFuncAr) + { + $useNodes = []; + + $this->useBlockArToNodes($useNodes); + + $this->fileNode = $this->factory->namespace($this->namespace); + + if(count($useNodes) > 0){ + + $this->fileNode->addStmts($useNodes); + } + + $this->fileNode->addStmt($this->classNode); + + $this->fileName = $this->className; + + return $this->fileNode->getNode(); + } + + private function useBlockArToNodes(&$stmNode) + { + + foreach ($this->useBlockAr as $useName=>$useAlias){ + + if($useAlias){ // the second must be alias : use class as foo + $node = $this->factory->use($useName)->as($useAlias); + }else {//== 1 + $node = $this->factory->use($useName); + } + + $stmNode[] = $node; + } + } + + public function handleAfterTraversTrait(&$nodes,&$mFuncAr) + { + $useNodes = []; + $this->useBlockArToNodes($useNodes); + + // use Proxied_Foo{} + $useTraitNode =$this->factory->useTrait($this->extendTraitName); + + foreach ($this->trailUseAsArray as $alias) + { + // $extendMethodName::thisfuncName as $this->extendTraitName.'_'.$thisFuncName; + $useTraitNode->with($this->factory->traitUseAdaptation($this->extendTraitName,$alias)->as($this->extendTraitName.'_'.$alias)); + } + + $this->traitNode->addStmt($useTraitNode); + + $this->fileNode = $this->factory->namespace($this->namespace) + ->addStmts($useNodes) + ->addStmt($this->traitNode); + + $this->fileName = $this->traitName; + + return $this->fileNode->getNode(); + } + + public function handleAfterTravers(&$nodes,&$mFuncAr) + { + return call_user_func_array([$this,$this->handleEndTraversFunc],[&$nodes,&$mFuncAr]); + } + + function handleLeaveNamespace(&$nodes) + { + // do nothing + } + + function handlerUseNode(&$nodes) + { + assert($nodes instanceof Node\Stmt\Use_); + foreach ($nodes->uses as $uses) + { +// $block= array($uses->name->toString()); +// if(isset($uses->alias)){ +// $block[]= $uses->alias->name; +// } + + $this->useBlockAr[$uses->name->toString()] = $uses->alias ? $uses->alias->name : null; + } + + } +} diff --git a/lib/pinpoint/Common/GenProxiedClassFileHelper.php b/lib/pinpoint/Common/GenProxiedClassFileHelper.php new file mode 100644 index 0000000..e60d452 --- /dev/null +++ b/lib/pinpoint/Common/GenProxiedClassFileHelper.php @@ -0,0 +1,182 @@ +orgDir = dirname($fullFile); + $this->orgFile = $fullFile; + $this->prefix = $prefix; + } + + + /** rename the class Proxied_foo + * @param $node + */ + public function handleLeaveClassNode(&$node) + { + assert($node instanceof Node\Stmt\Class_); + $className =$this->prefix.$node->name->toString(); + + $node->name = new Node\Identifier($className); + + $this->className = $this->namespace.'\\'.$className; + $this->name = $this->className; + + if($node->flags & Node\Stmt\Class_::MODIFIER_FINAL) + { + /// remove FINAL flag + $node->flags = $node->flags & ( ~(Node\Stmt\Class_::MODIFIER_FINAL) ); + } + } + + /** + * rename trait Foo{} => trait Proxed_Foo{} + * @param $node + */ + public function handleLeaveTraitNode(&$node) + { + assert($node instanceof Node\Stmt\Trait_); + $className =$this->prefix.$node->name->toString(); + + $node->name = new Node\Identifier($className); + + $this->traitName = $this->namespace.'\\'.$className; + $this->name = $this->traitName; + } + + + public function handleLeaveMethodNode(&$node,&$info) + { + assert($node instanceof Node\Stmt\ClassMethod); + if($node->flags & Node\Stmt\Class_::MODIFIER_PRIVATE) + { + // unset private + $node->flags = $node->flags &(~Node\Stmt\Class_::MODIFIER_PRIVATE); + + // set protect + $node->flags = $node->flags | (Node\Stmt\Class_::MODIFIER_PROTECTED); + } + + if($node->flags & Node\Stmt\Class_::MODIFIER_FINAL) + { + $node->flags = $node->flags &(~Node\Stmt\Class_::MODIFIER_FINAL); + } + + } + + + public function handleFullyQualifiedNode(&$node) + { + assert($node instanceof Node\Name\FullyQualified); + + $newNode = new Node\Name($node->toString()); + + return $newNode; + } + + public function addRequiredFile($fullName) + { + // modify the namespace + if(!in_array($fullName,$this->appendingFile)) + { + $this->appendingFile[] = $fullName; + } + } + + public function handleMagicConstNode(&$node) + { + switch ($node->getName()) + { + case '__FILE__': + return new Node\Scalar\String_($this->orgFile); + break; + case '__DIR__': + return new Node\Scalar\String_($this->orgDir); + break; + case '__FUNCTION__': + return new Node\Scalar\String_($this->classMethod); + break; + case '__CLASS__': + return new Node\Scalar\String_($this->className); + break; + case '__METHOD__': + return new Node\Scalar\String_($this->classMethod); + break; + case '__NAMESPACE__': + return new Node\Scalar\String_($this->namespace); + break; + default: + break; + } + + } + + + public function handleLeaveNamespace(&$nodes) + { + //todo + // This is just a temporary solution,just some tricks on origNode. + // Maybe one day php-parse could handle such scene + assert($nodes instanceof Node\Stmt\Namespace_); + foreach ($this->appendingFile as $fullPath) + { + $expression= new Node\Stmt\Expression( + new Node\Expr\Include_( + new Node\Expr\BinaryOp\Concat(new Node\Expr\ConstFetch( new Node\Name("AOP_CACHE_DIR")),new Node\Scalar\String_($fullPath)) + ,Node\Expr\Include_::TYPE_REQUIRE + ), ['startTokenPos'=>$nodes->getStartTokenPos(),'endTokenPos'=> $nodes->getEndTokenPos()] + ); + $nodes->stmts[] = $expression; + $originNode = $nodes->getAttribute("origNode"); + $originNode->stmts[] = $expression; + } + + return $nodes; + } + + public function handleAfterTravers(&$nodes,&$mFuncAr) + { + + return $nodes; + } + + function handlerUseNode(&$nodes) + { + // do nothing + } +} diff --git a/lib/pinpoint/Common/GenRequiredBIFileHelper.php b/lib/pinpoint/Common/GenRequiredBIFileHelper.php new file mode 100644 index 0000000..0fb97a9 --- /dev/null +++ b/lib/pinpoint/Common/GenRequiredBIFileHelper.php @@ -0,0 +1,347 @@ +namespace = $np; + $this->factory = new BuilderFactory; + $this->useArray = []; + $this->fileNode = []; + $this->classNode = []; + $this->funcNodes = []; + } + + //$args = \pinpoint_get_func_ref_args(); + private function createGetArgsStm($paraName) + { + if(function_exists('pinpoint_get_func_ref_args')){ + $getArgsStm = new Node\Stmt\Expression( + new Node\Expr\Assign( + new Node\Expr\Variable($paraName), + new Node\Expr\FuncCall( + new Node\Name\FullyQualified('pinpoint_get_func_ref_args'), + [ + + ] + ) + ) + ); + } + else{ + $getArgsStm = new Node\Stmt\Expression( + new Node\Expr\Assign( + new Node\Expr\Variable($paraName), + new Node\Expr\ArrayDimFetch( + new Node\Expr\ArrayDimFetch( + $this->factory->funcCall('debug_backtrace'), + new Node\Scalar\LNumber(0) + ), + new Node\Scalar\String_('args') + ) + ) + ); + } + + return $getArgsStm; + } + + public function extendsFunc($funcName,$info) + { + + list($mode, $namespace, $className) = $info; + $np = $namespace . '\\' . $className; + + if(!in_array($np,$this->useArray)){ + $this->useArray[] = $np; + } + + $funcVar = new Node\Arg(new Node\Scalar\String_($funcName)); + + $selfVar = new Node\Arg(new Node\Expr\ConstFetch(new Node\Name('null'))); + + // funcName($statement1,$statement2) + $biHelper = new GenerateBIHelper(new \ReflectionFunction($funcName),$this->factory); + + $thisFunc = $this->factory->function($funcName)->addParams($biHelper->getStmParamsDefine()); + + $thisFunc->addStmt($this->createGetArgsStm('args')); + + // $var = new commPlugins(__METHOD__,this,$args) + $varName = $className.'_'.$funcName.'_var'; + $retName = $className.'_'.$funcName.'_ret'; + $newPluginsStm = new Node\Stmt\Expression(new Node\Expr\Assign(new Node\Expr\Variable($varName), + $this->factory->new($className,[$funcVar,$selfVar, new Node\Expr\Variable('args')]))); + $thisFunc->addStmt($newPluginsStm); + + $tryBlock = []; + $catchNode = []; + + if ($mode & PluginParser::BEFORE) + { + // $var->onBefore(); + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall(new Node\Expr\Variable($varName), "onBefore")); + } + + // $ret = call_user_func_array("function",parater) + $tryBlock[] = new Node\Stmt\Expression(new Node\Expr\Assign( + new Node\Expr\Variable($retName), + new Node\Expr\FuncCall( + new Node\Name("call_user_func_array"), + [ + new Node\Arg(new Node\Scalar\String_($funcName)), + new Node\Expr\Variable('args'), + ] + ) + ) + ); + + /// $var->onEnd($ret); + if($mode & PluginParser::END) + { + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall( + new Node\Expr\Variable($varName), + "onEnd", + [new Node\Expr\Variable($retName)] + ) + ); + } + + /// return $var; + $tryBlock[] = new Node\Stmt\Return_(new Node\Expr\Variable($retName)); + + $expArgs = []; + $expArgs[] = new Node\Arg(new Node\Expr\Variable('e')) ; + + if ($mode & PluginParser::EXCEPTION) { + + $catchBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall(new Node\Expr\Variable($varName), + "onException",$expArgs)); + + } + + $catchBlock[] = new Node\Stmt\Throw_(new Node\Expr\Variable("e")); + + $catchNode[] = new Node\Stmt\Catch_([new Node\Name('\Exception')], + new Node\Expr\Variable('e'), + $catchBlock); + + $tryCatchFinallyNode = new Node\Stmt\TryCatch($tryBlock,$catchNode); + //try {}catch{} + $thisFunc->addStmt($tryCatchFinallyNode); + + $this->funcNodes[] = $thisFunc; + } + + + /// $mode,$np,$className + public function extendsMethod($dstClass,$thisFuncName,$info) + { + + list($mode, $namespace, $className) = $info; + + $np = $namespace . '\\' . $className; + + if(!in_array($np,$this->useArray)){ + $this->useArray[] = $np; + } + + try{ + $refMethod = new \ReflectionMethod($dstClass,$thisFuncName); + }catch (\ReflectionException $e) + { + return; + } + + $biHelper = new GenerateBIHelper($refMethod,$this->factory); + + $funcVar = new Node\Arg(new Node\Scalar\MagicConst\Method()); + + /// funcName($a,$b,$c) + $thisMethod = $this->factory->method($thisFuncName)->addParams( + $biHelper->getStmParamsDefine()); + + + if($refMethod->isStatic()){ + $thisMethod->makeStatic(); + $selfVar = new Node\Arg(new Node\Expr\ConstFetch(new Node\Name('null'))); + }else{ + $selfVar = new Node\Arg(new Node\Expr\Variable('this')); + } + + if($refMethod->isFinal()){ + throw new \Exception("$dstClass::$thisFuncName is a Final, aop not working"); + } + + if($refMethod->isPrivate()){ + throw new \Exception("$dstClass::$thisFuncName is a private, aop not working"); + } + + if($refMethod->isProtected()){ + $thisMethod->makeProtected(); + }else { + $thisMethod->makePublic(); + } + + $varName = $className.'_'.$thisFuncName.'_var'; + $retName = $className.'_'.$thisFuncName.'_ret'; + + //$args = \func_get_args(); +// $getArgsStm = new Node\Stmt\Expression( +// new Node\Expr\Assign( +// new Node\Expr\Variable("args"), +// new Node\Expr\FuncCall( +// new Node\Name\FullyQualified('func_get_args'), +// [ +// +// ] +// ) +// ) +// ); + + $thisMethod->addStmt($this->createGetArgsStm('args')); + + + // $var = new commPlugins(__METHOD__,this,$args) + $newPluginsStm = new Node\Stmt\Expression(new Node\Expr\Assign(new Node\Expr\Variable($varName), + $this->factory->new($className,[$funcVar,$selfVar,new Node\Expr\Variable('args')]))); + $thisMethod->addStmt($newPluginsStm); + + + $tryBlock = []; + $catchNode = []; + + // $var->onBefore(); + if ($mode & PluginParser::BEFORE) + { + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall(new Node\Expr\Variable($varName), "onBefore")); + } + + // $ret = call_user_func_array + $tryBlock[] = new Node\Stmt\Expression(new Node\Expr\Assign( + new Node\Expr\Variable($retName), + new Node\Expr\FuncCall( + new Node\Name("call_user_func_array"), + [ + new Node\Arg(new Node\Expr\Array_( + [ + new Node\Expr\ArrayItem(new Node\Scalar\String_('parent')), + new Node\Scalar\MagicConst\Function_() + ] + )), + new Node\Expr\Variable('args') + ] + ) + ) + ); + + /// $var->onEnd($ret); + if($mode & PluginParser::END) + { + $tryBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall( + new Node\Expr\Variable($varName), + "onEnd", + [new Node\Expr\Variable($retName)] + ) + ); + } + + /// return $var; + $tryBlock[] = new Node\Stmt\Return_(new Node\Expr\Variable($retName)); + + $expArgs = []; + $expArgs[] = new Node\Arg(new Node\Expr\Variable('e')) ; + + if ($mode & PluginParser::EXCEPTION) { + + $catchBlock[] = new Node\Stmt\Expression( + $this->factory->methodCall(new Node\Expr\Variable($varName), + "onException",$expArgs)); + + } + + $catchBlock[] = new Node\Stmt\Throw_(new Node\Expr\Variable("e")); + + $catchNode[] = new Node\Stmt\Catch_([new Node\Name('\Exception')], + new Node\Expr\Variable('e'), + $catchBlock); + + $tryCatchFinallyNode = new Node\Stmt\TryCatch($tryBlock,$catchNode); + + $thisMethod->addStmt($tryCatchFinallyNode); + + if( !array_key_exists($dstClass, $this->classNode)) + { + $this->classNode[$dstClass] = $this->factory->class($dstClass)->extend('\\'.$dstClass); + } + + $this->classNode[$dstClass]->addStmt($thisMethod); + } + + public function loadToFile($fullPath) + { + $useNodes = []; + foreach ($this->useArray as $useAlias){ + $useNodes[] = $this->factory->use($useAlias); + } + + $this->fileNode = $this->factory->namespace($this->namespace) + ->addStmts($useNodes) + ->addStmts( + $this->classNode + )->addStmts($this->funcNodes); + + $stmts = array($this->fileNode->getNode()); + $prettyPrinter = new PrettyPrinter\Standard(); + $context = $prettyPrinter->prettyPrintFile($stmts); + Util::flushStr2File($context,$fullPath); + } + +} diff --git a/lib/pinpoint/Common/GenerateBIHelper.php b/lib/pinpoint/Common/GenerateBIHelper.php new file mode 100644 index 0000000..a9c946a --- /dev/null +++ b/lib/pinpoint/Common/GenerateBIHelper.php @@ -0,0 +1,101 @@ +_reflectinst = $reflectinst; + $this->_factory = $factory; + assert($this->_factory instanceof BuilderFactory); + } + + public function getStmParamsDefine() + { + foreach ($this->_reflectinst->getParameters() as $param) + { + $pNode = $this->makeParam($param); + + if($param->isPassedByReference()) + $pNode->makeByRef(); + $this->_stmArgsNode[] = $pNode; + } + return $this->_stmArgsNode;; + } + + private function makeParam($param) + { + if($param->isArray()){ + return $this->makeArrayParam($param); + }else{ + return $this->makeOtherParam($param); + } + } + + private function makeArrayParam($param) + { + $node = $this->_factory->param($param->getName())->setType('array'); + + if ($param->isVariadic()) + $node->makeVariadic(); + elseif ($param->isOptional()) +// new Node\Name('null') + $node->setDefault(null); + + if($param->isPassedByReference()) + $node->makeByRef(); + + return $node; + } + + private function makeOtherParam($param) + { + $node = $this->_factory->param($param->getName()); + + if ($param->isVariadic()) + $node->makeVariadic(); + elseif($param->isOptional()) + $node->setDefault(null); + + if($param->isPassedByReference()) + $node->makeByRef(); + + return $node; + } + + public function getArrayParams() + { + if($this->_args){ + return $this->_args; + } + $vars =[]; + foreach ($this->_reflectinst->getParameters() as $param) + { + $name = $param->getName(); + + $arItemNode = new Node\Expr\ArrayItem(new Node\Expr\Variable($name)); + + if($param->isPassedByReference()) + $arItemNode->byRef = true; + $vars[] =$arItemNode; + } + + $this->_args = new Node\Expr\Array_($vars); + return $this->_args; + } +} \ No newline at end of file diff --git a/lib/pinpoint/Common/OrgClassParse.php b/lib/pinpoint/Common/OrgClassParse.php new file mode 100644 index 0000000..96155d7 --- /dev/null +++ b/lib/pinpoint/Common/OrgClassParse.php @@ -0,0 +1,142 @@ +className = $cl; + $this->mFuncAr = $info; + $this->originFile = $fullPath; + + + $this->lexer = new Lexer\Emulative([ + 'usedAttributes' => [ + 'comments', + 'startLine', + 'endLine', + 'startTokenPos', + 'endTokenPos', + ], + ]); + + $this->parser = new Parser\Php7($this->lexer, [ + 'useIdentifierNodes' => true, + 'useConsistentVariableNodes' => true, + 'useExpressionStatements' => true, + 'useNopStatements' => false, + ]); + + $this->traverser = new NodeTraverser(); + $this->traverser->addVisitor(new NodeVisitor\CloningVisitor()); + $this->traverser->addVisitor(new CodeVisitor($this)); + + $this->printer = new PrettyPrinter\Standard(); + + $this->proxiedClassFile = new GenProxiedClassFileHelper($fullPath,OrgClassParse::PRE_FIX); + $this->originClassFile = new GenOriginClassFileHelper(OrgClassParse::PRE_FIX); + + $this->parseOriginFile(); + } + + protected function parseOriginFile() + { + $code = file_get_contents($this->originFile); + + $this->rawOrigStmts = $this->parser->parse($code); + + $this->originClassNode = $this->traverser->traverse($this->rawOrigStmts); + + } + + /// convert $node to file + public function orgClassNodeDoneCB($node,$fullName) + { + $fullPath = AOP_CACHE_DIR.'/'.str_replace('\\','/',$fullName).'.php'; + // try to keep blank and filenu + $orgClassContext = $this->printer->printFormatPreserving( + $node, + $this->rawOrigStmts, + $this->lexer->getTokens()); + + Util::flushStr2File($orgClassContext,$fullPath); + $this->classIndex[$fullName] = $fullPath; + } + + /// convert $node to file + public function shadowClassNodeDoneCB(&$node,$fullName) + { + + $fullPath = AOP_CACHE_DIR.'/'.str_replace('\\','/',$fullName).'.php'; + $context= $this->printer->prettyPrintFile(array($node)); + Util::flushStr2File($context,$fullPath); + $this->classIndex[$fullName] = $fullPath; + } + + + public function generateAllClass() + { + /// ast to source + return $this->classIndex; + } +} diff --git a/lib/pinpoint/Common/PinpointClassLoader.php b/lib/pinpoint/Common/PinpointClassLoader.php new file mode 100644 index 0000000..717f485 --- /dev/null +++ b/lib/pinpoint/Common/PinpointClassLoader.php @@ -0,0 +1,84 @@ +classMap = $classMap; + + $this->origin = $origin; + assert($origin); + } + + public function findFile(string $classFullName) + { + $file = $this->classMap->findFile($classFullName); + + if( ! $file ) + { + $file = $this->origin->findFile($classFullName); + if ($file !== false) + { + $file = realpath($file) ?: $file; + } + } + return $file; + } + + public function loadClass($class) + { + $file = $this->findFile($class); + + if ($file !== false) { + include $file; + } + } + + /** + * register pinpoint aop class loader, wrapped vendor class loader + * @param $classIndex + * @return bool + */ + public static function init($classIndex) + { + $loaders = spl_autoload_functions(); + foreach ($loaders as &$loader) { + $loaderToUnregister = $loader; + if (is_array($loader) && ($loader[0] instanceof ClassLoader)) { + // unregister composer loader + spl_autoload_unregister($loaderToUnregister); + // $originalLoader = $loader[0]; + // replace composer loader with aopclassLoader + $loader[0] = new PinpointClassLoader($loader[0],$classIndex); + spl_autoload_register($loader,true,true); + self::$inInitalized = true; + } + } + + return self::$inInitalized; + + } + +} diff --git a/lib/pinpoint/Common/PinpointDriver.php b/lib/pinpoint/Common/PinpointDriver.php new file mode 100644 index 0000000..05dc6fa --- /dev/null +++ b/lib/pinpoint/Common/PinpointDriver.php @@ -0,0 +1,101 @@ +classMap; + } + + public static function getInstance(){ + + if (!self::$instance) { + self::$instance = new static(); + } + + return self::$instance; + } + + public function __construct() + { + $this->clAr = []; + } + + public function init(AopClassMap $classMap) + { + /// checking the cached file exist, if exist load it + if(!$classMap->updateSelf()) + { + PinpointClassLoader::init($classMap); + return ; + } + + $pluFiles = glob(PLUGINS_DIR."/*Plugin.php"); + $pluParsers = []; + foreach ($pluFiles as $file) + { + $pluParsers[] = new PluginParser($file,$this->clAr); + } + + foreach ($this->clAr as $cl=> $info) + { + if(empty($cl)) + { + continue; + } + + $fullPath = Util::findFile($cl); + if(!$fullPath) + { + continue; + } + + $osr = new OrgClassParse($fullPath,$cl,$info); + foreach ($osr->classIndex as $clName=>$path) + { + $classMap->insertMapping($clName,$path); + } + } + + $classMap->persistenceClassMapping(); + + PinpointClassLoader::init($classMap); + + } + + +} diff --git a/lib/pinpoint/Common/PluginParser.php b/lib/pinpoint/Common/PluginParser.php new file mode 100644 index 0000000..a18dd6c --- /dev/null +++ b/lib/pinpoint/Common/PluginParser.php @@ -0,0 +1,133 @@ +namespace; + } + + /** + * user could merge all Plugins, if duplicate, warning the innocent user + * @return mixed + */ + public function getClArray() + { + return $this->clArray; + } + + /** + * @param mixed $namespace + */ + public function setNamespace($namespace) + { + $this->namespace = $namespace; + } + + /** + * @return mixed + */ + public function getClassName() + { + return $this->className; + } + + /** + * @param mixed $className + */ + public function setClassName($className) + { + $this->className = $className; + } + + public function __construct($classFile,&$clArray) + { + assert(file_exists($classFile)); + $this->pluginsFile = $classFile; + $this->clArray = &$clArray; + $this->run(); + } + + public function run() + { + // todo , need add php5? php7 include php5 ? + $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); + $nodes = $parser->parse(file_get_contents($this->pluginsFile)); + + // find np and cl + + $nodeTraverser = new NodeTraverser; + $nodeTraverser->addVisitor(new PluginVisitor($this)); + $nodeTraverser->traverse($nodes); + } + + public function insertFunc($funcName, $mode) + { + $split = stripos ($funcName,'::'); + $uCl = substr($funcName,0,$split); + $uFunc = substr($funcName,$split+2); + + /// not Internal func + if(!array_key_exists($uCl,$this->clArray)) + { + // Cl = APP\Foo + // func = open + $this->clArray[$uCl] = array( $uFunc => + array($mode,$this->namespace,$this->className)); + }elseif (!array_key_exists($uFunc,$this->clArray[$uCl])) + { + $this->clArray[$uCl][$uFunc]= array($mode,$this->namespace,$this->className); + } + else { + // when user tears the plugins, that only works on $mode + $this->clArray[$uCl][$uFunc][0] |= $mode; + } + } + +} diff --git a/lib/pinpoint/Common/PluginVisitor.php b/lib/pinpoint/Common/PluginVisitor.php new file mode 100644 index 0000000..6d03426 --- /dev/null +++ b/lib/pinpoint/Common/PluginVisitor.php @@ -0,0 +1,89 @@ +iParser = $parser; + return ; + } + throw new \Exception("illegal input"); + } + + ///$PluginsInfo => class + private function loadCommentFunc(&$node,$mode) + { + foreach( $node->getComments() as &$doc) + { + $funArray = Util::parseUserFunc(trim($doc->getText())); + + foreach ($funArray as $func) + { + $this->iParser->insertFunc(trim($func),$mode); + } + } + } + + public function enterNode(Node $node) + { + if ($node instanceof Node\Stmt\Namespace_) { + $this->iParser->setNamespace(trim($node->name->toString())); + } + elseif($node instanceof Node\Stmt\Class_) { + $this->iParser->setClassName(trim($node->name->toString())); + $this->loadCommentFunc($node, PluginParser::ALL); + } + } + + public function leaveNode(Node $node) + { + if($node instanceof Node\Stmt\ClassMethod) + { + $name = $node->name->toString(); + $node->getComments(); + switch($name) + { + case "onBefore": + $this->loadCommentFunc($node, PluginParser::BEFORE); + break; + case "onEnd": + $this->loadCommentFunc($node, PluginParser::END); + break; + case "onException": + $this->loadCommentFunc($node, PluginParser::EXCEPTION); + break; + default: + // do nothing + } + } + } +} \ No newline at end of file diff --git a/lib/pinpoint/Common/Util.php b/lib/pinpoint/Common/Util.php new file mode 100644 index 0000000..1e013d2 --- /dev/null +++ b/lib/pinpoint/Common/Util.php @@ -0,0 +1,105 @@ +findFile($class); + } + elseif (is_array($loader) && is_string($loader[0])){ + if(method_exists($loader[0],'findFile')){ + $address= call_user_func("$loader[0]::findFile",$class); + + } + } + + if($address){ + return realpath($address); + } + } + + return false; + } + + public static function parseUserFunc($str) + { + preg_match_all('#(?<=@hook:).*#', $str,$matched); + + if($matched){ + $func = []; + foreach ($matched[0] as $str){ + $func =array_merge($func , preg_split("# |\|#",$str,-1,PREG_SPLIT_NO_EMPTY)); + } + return $func; + } + + return []; + } + + public static function flushStr2File(&$context, $fullPath) + { + $dir = dirname($fullPath); + if (!is_dir($dir)) { + mkdir($dir, 0777, true); + } + file_put_contents($fullPath, $context); + } + + public static function isBuiltIn($name) + { + if (strpos($name, "\\") === 0) //build-in + { + if (strpos($name, "::") > 0){ + return static::U_Method; + }else{ + return static::U_Function; + } + } + + return null; + } + +} diff --git a/lib/pinpoint/Common/WrapperInternalClass.php b/lib/pinpoint/Common/WrapperInternalClass.php new file mode 100644 index 0000000..b703f35 --- /dev/null +++ b/lib/pinpoint/Common/WrapperInternalClass.php @@ -0,0 +1,55 @@ +objInstance = $oReflectionClass->newInstance(...$args); + } + + public function __call($name, $arguments) + { + + return call_user_func_array(array($this->objInstance,$name),$arguments); + } + + public static function __callStatic($name, $args) + { + try + { + + $ret = call_user_func_array(array(self::$originName,$name),$args); + }catch (Exception $e) + { + throw new \Exception($name." not find"); + } + + return $ret; + } +} \ No newline at end of file diff --git a/lib/pinpoint/test/ClassParseTest.php b/lib/pinpoint/test/ClassParseTest.php new file mode 100644 index 0000000..520e82a --- /dev/null +++ b/lib/pinpoint/test/ClassParseTest.php @@ -0,0 +1,90 @@ +[7,'pinpoint\\test','traitTestPlugin'] + ]; + + $osr = new OrgClassParse($fullpath,$cl,$info); + + foreach ($osr->classIndex as $class => $location) + { + $exp = str_replace('Cache','Comparison',$location); + self::assertFileEquals($exp,$location); + } + + $requireFile = $osr->requiredFile; + $expRequired= str_replace('Cache','Comparison',$requireFile); + self::assertFileEquals($requireFile,$expRequired); + } + + public function testClass() + { + $fullpath =__DIR__.'/TestClass.php'; + $cl = "pinpoint\\test\\TestClass"; + $info = [ + 'foo'=>[7,'pinpoint\\test','traitTestPlugin'], + 'fooUseYield'=>[3,'pinpoint\\test','traitTestPlugin'], + 'fooNoReturn'=>[4,'pinpoint\\test','traitTestPlugin'], + 'fooNoReturnButReturn'=>[4,'pinpoint\\test\\burden\\depress\\herb\\e\\e\f\\longNp','victim'], + 'fooNaughtyFinal'=>[7,'','over'], + '\PDO::query'=>[7,'pinpoint\\test','traitTestPlugin'], + '\curl_exec' =>[7,'pinpoint\\test','traitTestPlugin'], + 'fooTestACPrivate' =>[4,'pinpoint\\test','traitTestPlugin'], + 'fooTestCompatible'=>[4,'pinpoint\\test','traitTestPlugin'], + 'returnNothing'=>[7,'pinpoint\\test','traitTestPlugin'], + 'returnNothing_1'=>[7,'pinpoint\\test','traitTestPlugin'], + '__construct'=>[7,'pinpoint\\test','traitTestPlugin'] + ]; + + + $osr = new OrgClassParse($fullpath,$cl,$info); + + foreach ($osr->classIndex as $class => $location) + { + $exp = str_replace('Cache','Comparison',$location); + self::assertFileEquals($exp,$location); + } + + $requireFile = $osr->requiredFile; + $expRequired= str_replace('Cache','Comparison',$requireFile); + self::assertFileEquals($requireFile,$expRequired); + } +} diff --git a/lib/pinpoint/test/Comparison/pinpoint/test/Proxied_TestClass.php b/lib/pinpoint/test/Comparison/pinpoint/test/Proxied_TestClass.php new file mode 100644 index 0000000..e9fcf80 --- /dev/null +++ b/lib/pinpoint/test/Comparison/pinpoint/test/Proxied_TestClass.php @@ -0,0 +1,80 @@ +query('SELECT name, color, calories FROM fruit ORDER BY name'); + + } + + protected function fooTestACPrivate() + { + echo "I'm a private function"; + return "OK"; + } + public function fooTestCompatible(class1 $a,class2 $b,FooClass $c,FooClass4 $d) + { + return null; + } + + public function returnNothing(): void + { + return ; + } + public function returnNothing_1() + { + return ; + } +}require AOP_CACHE_DIR . 'pinpoint/test/TestClass_required.php'; diff --git a/lib/pinpoint/test/Comparison/pinpoint/test/Proxied_TestTrait.php b/lib/pinpoint/test/Comparison/pinpoint/test/Proxied_TestTrait.php new file mode 100644 index 0000000..b177647 --- /dev/null +++ b/lib/pinpoint/test/Comparison/pinpoint/test/Proxied_TestTrait.php @@ -0,0 +1,19 @@ +onBefore(); + parent::__construct($a, $b, $c); + $traitTestPlugin___construct_var->onEnd($traitTestPlugin___construct_ret); + } catch (\Exception $e) { + $traitTestPlugin___construct_var->onException($e); + throw $e; + } + } + public function foo($a, $b, $v, $d) : array + { + $traitTestPlugin_foo_var = new traitTestPlugin(__METHOD__, $this, $a, $b, $v, $d); + $traitTestPlugin_foo_ret = null; + try { + $traitTestPlugin_foo_var->onBefore(); + $traitTestPlugin_foo_ret = parent::foo($a, $b, $v, $d); + $traitTestPlugin_foo_var->onEnd($traitTestPlugin_foo_ret); + return $traitTestPlugin_foo_ret; + } catch (\Exception $e) { + $traitTestPlugin_foo_var->onException($e); + throw $e; + } + } + public function fooUseYield() + { + $traitTestPlugin_fooUseYield_var = new traitTestPlugin(__METHOD__, $this); + $traitTestPlugin_fooUseYield_ret = null; + try { + $traitTestPlugin_fooUseYield_var->onBefore(); + $traitTestPlugin_fooUseYield_ret = parent::fooUseYield(); + $traitTestPlugin_fooUseYield_var->onEnd($traitTestPlugin_fooUseYield_ret); + return $traitTestPlugin_fooUseYield_ret; + } catch (\Exception $e) { + throw $e; + } + } + public function fooNoReturn() + { + $traitTestPlugin_fooNoReturn_var = new traitTestPlugin(__METHOD__, $this); + $traitTestPlugin_fooNoReturn_ret = null; + try { + parent::fooNoReturn(); + } catch (\Exception $e) { + $traitTestPlugin_fooNoReturn_var->onException($e); + throw $e; + } + } + public function fooNoReturnButReturn() + { + $victim_fooNoReturnButReturn_var = new victim(__METHOD__, $this); + $victim_fooNoReturnButReturn_ret = null; + try { + $victim_fooNoReturnButReturn_ret = parent::fooNoReturnButReturn(); + return $victim_fooNoReturnButReturn_ret; + } catch (\Exception $e) { + $victim_fooNoReturnButReturn_var->onException($e); + throw $e; + } + } + public final function fooNaughtyFinal($a, $b, $c) + { + $over_fooNaughtyFinal_var = new over(__METHOD__, $this, $a, $b, $c); + $over_fooNaughtyFinal_ret = null; + try { + $over_fooNaughtyFinal_var->onBefore(); + $over_fooNaughtyFinal_ret = parent::fooNaughtyFinal($a, $b, $c); + $over_fooNaughtyFinal_var->onEnd($over_fooNaughtyFinal_ret); + return $over_fooNaughtyFinal_ret; + } catch (\Exception $e) { + $over_fooNaughtyFinal_var->onException($e); + throw $e; + } + } + protected function fooTestACPrivate() + { + $traitTestPlugin_fooTestACPrivate_var = new traitTestPlugin(__METHOD__, $this); + $traitTestPlugin_fooTestACPrivate_ret = null; + try { + $traitTestPlugin_fooTestACPrivate_ret = parent::fooTestACPrivate(); + return $traitTestPlugin_fooTestACPrivate_ret; + } catch (\Exception $e) { + $traitTestPlugin_fooTestACPrivate_var->onException($e); + throw $e; + } + } + public function fooTestCompatible(class1 $a, class2 $b, FooClass $c, FooClass4 $d) + { + $traitTestPlugin_fooTestCompatible_var = new traitTestPlugin(__METHOD__, $this, $a, $b, $c, $d); + $traitTestPlugin_fooTestCompatible_ret = null; + try { + $traitTestPlugin_fooTestCompatible_ret = parent::fooTestCompatible($a, $b, $c, $d); + return $traitTestPlugin_fooTestCompatible_ret; + } catch (\Exception $e) { + $traitTestPlugin_fooTestCompatible_var->onException($e); + throw $e; + } + } + public function returnNothing() : void + { + $traitTestPlugin_returnNothing_var = new traitTestPlugin(__METHOD__, $this); + $traitTestPlugin_returnNothing_ret = null; + try { + $traitTestPlugin_returnNothing_var->onBefore(); + parent::returnNothing(); + $traitTestPlugin_returnNothing_var->onEnd($traitTestPlugin_returnNothing_ret); + } catch (\Exception $e) { + $traitTestPlugin_returnNothing_var->onException($e); + throw $e; + } + } + public function returnNothing_1() + { + $traitTestPlugin_returnNothing_1_var = new traitTestPlugin(__METHOD__, $this); + $traitTestPlugin_returnNothing_1_ret = null; + try { + $traitTestPlugin_returnNothing_1_var->onBefore(); + parent::returnNothing_1(); + $traitTestPlugin_returnNothing_1_var->onEnd($traitTestPlugin_returnNothing_1_ret); + } catch (\Exception $e) { + $traitTestPlugin_returnNothing_1_var->onException($e); + throw $e; + } + } +} \ No newline at end of file diff --git a/lib/pinpoint/test/Comparison/pinpoint/test/TestClass_required.php b/lib/pinpoint/test/Comparison/pinpoint/test/TestClass_required.php new file mode 100644 index 0000000..438237a --- /dev/null +++ b/lib/pinpoint/test/Comparison/pinpoint/test/TestClass_required.php @@ -0,0 +1,36 @@ +onBefore(); + $traitTestPlugin_query_ret = call_user_func_array(array('parent', __FUNCTION__), $args); + $traitTestPlugin_query_var->onEnd($traitTestPlugin_query_ret); + return $traitTestPlugin_query_ret; + } catch (\Exception $e) { + $traitTestPlugin_query_var->onException($e); + throw $e; + } + } +} +function curl_exec($ch) +{ + $args = debug_backtrace()[0]['args']; + $traitTestPlugin_curl_exec_var = new traitTestPlugin('curl_exec', null, $args); + try { + $traitTestPlugin_curl_exec_var->onBefore(); + $traitTestPlugin_curl_exec_ret = call_user_func_array('curl_exec', $args); + $traitTestPlugin_curl_exec_var->onEnd($traitTestPlugin_curl_exec_ret); + return $traitTestPlugin_curl_exec_ret; + } catch (\Exception $e) { + $traitTestPlugin_curl_exec_var->onException($e); + throw $e; + } +} \ No newline at end of file diff --git a/lib/pinpoint/test/Comparison/pinpoint/test/TestTrait.php b/lib/pinpoint/test/Comparison/pinpoint/test/TestTrait.php new file mode 100644 index 0000000..2dd8c7b --- /dev/null +++ b/lib/pinpoint/test/Comparison/pinpoint/test/TestTrait.php @@ -0,0 +1,24 @@ +onBefore(); + $this->Proxied_TestTrait_getReturnType(); + $traitTestPlugin_getReturnType_var->onEnd($traitTestPlugin_getReturnType_ret); + } catch (\Exception $e) { + $traitTestPlugin_getReturnType_var->onException($e); + throw $e; + } + } +} \ No newline at end of file diff --git a/lib/pinpoint/test/Comparison/pinpoint/test/TestTrait_required.php b/lib/pinpoint/test/Comparison/pinpoint/test/TestTrait_required.php new file mode 100644 index 0000000..f60a457 --- /dev/null +++ b/lib/pinpoint/test/Comparison/pinpoint/test/TestTrait_required.php @@ -0,0 +1,3 @@ +getMethods() as $method) { + if(!$method->isFinal()) + $bi->extendsMethod($className, $method->getName(), [7, 'pinpoint', 'commPlugins']); + } + } + + $moduleName =['curl']; + + foreach ($moduleName as $mName) { + $funs = get_extension_funcs($mName); + + foreach ($funs as $func) { + $bi->extendsFunc($func, [7, 'pinpoint', 'commPlugins']); + } + + } + if(file_exists("required_test.php")){ + unlink( "required_test.php"); + } + $bi->loadToFile("required_test.php"); + self::assertFileExists("required_test.php"); + require "required_test.php"; + } +} + diff --git a/lib/pinpoint/test/PluginParserTest.php b/lib/pinpoint/test/PluginParserTest.php new file mode 100644 index 0000000..3c111e0 --- /dev/null +++ b/lib/pinpoint/test/PluginParserTest.php @@ -0,0 +1,49 @@ +run(); +// self::assertEquals($var->getClassName(), "CommonPlugin"); +// self::assertEquals($var->getNamespace(), 'Pinpoint\Plugins'); +// $array = $var->getClArray(); +// self::assertArrayHasKey("app\Foo::foo_p1",$array); +// self::assertArrayHasKey("app\Foo::print_r",$array); +// self::assertArrayHasKey("app\Foo::curl_init",$array); +// self::assertArrayNotHasKey("test",$array); +// self::assertArrayNotHasKey("format",$array); +// self::assertArrayHasKey("app\Foo::curl_setopt",$array); +// self::assertEquals($array['app\Foo::foo_p1']['mode'] ,7); +// self::assertEquals($array['app\Foo::print_r']['mode'] ,1); +// self::assertEquals($array['app\Foo::curl_init']['mode'] ,7); + + } +} diff --git a/lib/pinpoint/test/TestClass.php b/lib/pinpoint/test/TestClass.php new file mode 100644 index 0000000..325b1e2 --- /dev/null +++ b/lib/pinpoint/test/TestClass.php @@ -0,0 +1,80 @@ +query('SELECT name, color, calories FROM fruit ORDER BY name'); + + } + + private function fooTestACPrivate() + { + echo "I'm a private function"; + return "OK"; + } + public function fooTestCompatible(class1 $a,class2 $b,FooClass $c,FooClass4 $d) + { + return null; + } + + public function returnNothing(): void + { + return ; + } + public function returnNothing_1() + { + return ; + } +} diff --git a/lib/pinpoint/test/TestTrait.php b/lib/pinpoint/test/TestTrait.php new file mode 100644 index 0000000..65f7155 --- /dev/null +++ b/lib/pinpoint/test/TestTrait.php @@ -0,0 +1,19 @@ +