├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── docs └── README.md ├── phpunit.xml.dist ├── sami.doc.inc ├── src ├── autoload.php ├── collection │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── composer.json │ ├── phpunit.xml.dist │ ├── src │ │ ├── ActiveData.php │ │ ├── Collection.php │ │ ├── CollectionInterface.php │ │ ├── Configuration.php │ │ ├── JsonMessage.php │ │ ├── Language.php │ │ ├── LiteCollection.php │ │ └── SimpleCollection.php │ └── test │ │ ├── LanguageTest.php │ │ ├── boot.php │ │ └── testdata │ │ ├── en │ │ └── response.php │ │ └── zh-CN │ │ └── response.php ├── data-parser │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── composer.json │ ├── phpunit.xml.dist │ ├── src │ │ ├── AbstractDataParser.php │ │ ├── DataParserAwareTrait.php │ │ ├── DataParserInterface.php │ │ ├── JsonParser.php │ │ ├── MsgPackParser.php │ │ ├── PhpParser.php │ │ └── SwooleParser.php │ └── test │ │ ├── JsonParserTest.php │ │ ├── PhpParserTest.php │ │ └── boot.php ├── dev-helper │ └── Console │ │ └── DevController.php ├── di │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── composer.json │ ├── example │ │ └── di.php │ ├── phpunit.xml.dist │ ├── src │ │ ├── CallableResolver.php │ │ ├── CallableResolverAwareTrait.php │ │ ├── Container.php │ │ ├── DIManager.php │ │ ├── Exception │ │ │ ├── DependencyResolutionException.php │ │ │ └── NotFoundException.php │ │ ├── NameAliasTrait.php │ │ ├── ObjectItem.php │ │ └── ServiceProviderInterface.php │ └── test │ │ ├── ContainerTest.php │ │ ├── MakeByMethod.php │ │ ├── MakeByStatic.php │ │ ├── SomeClass.php │ │ └── boot.php └── helper-utils │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── composer.json │ ├── phpunit.xml.dist │ ├── src │ ├── Helper │ │ ├── AssertHelper.php │ │ ├── DataHelper.php │ │ ├── DateHelper.php │ │ ├── DsnHelper.php │ │ ├── FormatHelper.php │ │ ├── Http.php │ │ ├── IntHelper.php │ │ ├── SslHelper.php │ │ └── UtilHelper.php │ ├── Traits │ │ ├── AopProxyAwareTrait.php │ │ ├── Config │ │ │ ├── ConfigTrait.php │ │ │ ├── LiteConfigTrait.php │ │ │ ├── LiteOptionsTrait.php │ │ │ └── OptionsTrait.php │ │ ├── Event │ │ │ ├── EventTrait.php │ │ │ ├── FixedEventStaticTrait.php │ │ │ ├── FixedEventTrait.php │ │ │ ├── LiteEventStaticTrait.php │ │ │ └── LiteEventTrait.php │ │ ├── LiteContainerStaticTrait.php │ │ ├── LiteContainerTrait.php │ │ ├── LogProfileTrait.php │ │ ├── LogShortTrait.php │ │ ├── NameAliasStaticTrait.php │ │ ├── NameAliasTrait.php │ │ ├── PathAliasTrait.php │ │ ├── PathResolverTrait.php │ │ └── RuntimeProfileTrait.php │ └── Util │ │ ├── AopProxy.php │ │ ├── DataProxy.php │ │ ├── DataResult.php │ │ ├── DeferredCallable.php │ │ ├── Pipeline.php │ │ └── PipelineInterface.php │ └── test │ └── boot.php ├── test └── boot.php └── toolkit /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # 对所有文件生效 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | # 对后缀名为 md 的文件生效 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | 16 | [*.xml|*.xml.dist] 17 | indent_size = 2 18 | 19 | [*.json] 20 | indent_size = 2 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .phpintel/ 3 | caches/ 4 | vendor/ 5 | !README.md 6 | !.gitkeep 7 | composer.lock 8 | *.swp 9 | *.log 10 | *.pid 11 | *.patch 12 | *.cache 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 inhere 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP工具包 2 | 3 | [![Php Version](https://img.shields.io/badge/php-%3E=7.1.0-brightgreen.svg?maxAge=2592000)](https://packagist.org/packages/toolkit/str-utils) 4 | 5 | php的一些有用的基础工具库实现和收集整理。 6 | 7 | > 本仓库是主仓库,开发后推送到各个组件仓库。如果只需要一个或部分工具,可以单独配置require 8 | 9 | **1. 字符串工具** 10 | 11 | 常用的字符串操作帮助工具类库,以及一些 html,json 编解码, token,url 等工具类 12 | 13 | - 独立包名 [toolkit/str-utils](https://github.com/php-toolkit/str-utils) 14 | - 在本仓库的 [libs/str-utils](libs/str-utils) 15 | 16 | **2. 数组工具** 17 | 18 | 常用的数组操作帮助工具类库 19 | 20 | - 独立包名 [toolkit/arr-utils](https://github.com/php-toolkit/arr-utils) 21 | - 在本仓库的 [libs/arr-utils](libs/arr-utils) 22 | 23 | **3. 对象工具** 24 | 25 | 常用的对象操作帮助工具类、traits库 26 | 27 | - 独立包名 [toolkit/obj-utils](https://github.com/php-toolkit/obj-utils) 28 | - 在本仓库的 [libs/obj-utils](libs/obj-utils) 29 | 30 | **4. 系统工具** 31 | 32 | 常用的系统操作帮助工具类库。系统环境信息,执行命令,简单的进程操作使用类(fork,run,stop,wait ...)等 33 | 34 | - 独立包名 [toolkit/sys-utils](https://github.com/php-toolkit/sys-utils) 35 | - 在本仓库的 [libs/sys-utils](libs/sys-utils) 36 | 37 | **5. php工具** 38 | 39 | 常用的php操作帮助工具类库。php环境信息,数据打印,`.env`加载,简单的autoload类等 40 | 41 | - 独立包名 [toolkit/php-utils](https://github.com/php-toolkit/php-utils) 42 | - 在本仓库的 [libs/php-utils](libs/php-utils) 43 | 44 | **6. 文件系统工具** 45 | 46 | 常用的文件系统操作帮助工具类库。文件查找,创建,判断,信息获取,内容读取等,目录的创建,权限,拷贝,删除等。 47 | 48 | - 独立包名 [toolkit/file-utils](https://github.com/php-toolkit/file-utils) 49 | - 在本仓库的 [libs/file-utils](libs/file-utils) 50 | 51 | **7. CLI工具** 52 | 53 | 常用的php cli环境的帮助工具类库。cli下的内容输出,读取。丰富的颜色内容输出,cli下的php文件高亮,简单的光标操作。 54 | 55 | - 独立包名 [toolkit/cli-utils](https://github.com/php-toolkit/cli-utils) 56 | - 在本仓库的 [libs/cli-utils](libs/cli-utils) 57 | 58 | **8. 数据收集器** 59 | 60 | 数据收集器 `Collection` 实现。可用于配置数据管理、数据收集、数据迭代等。 61 | 62 | - 独立包名 [toolkit/collection](https://github.com/php-toolkit/collection) 63 | - 在本仓库的 [libs/collection](libs/collection) 64 | 65 | **9. 简单的DI容器实现** 66 | 67 | 简单的 `psr/container` 对象管理容器实现 68 | 69 | - 独立包名 [toolkit/di](https://github.com/php-toolkit/di) 70 | - 在本仓库的 [libs/di](libs/di) 71 | 72 | **10. 数据解析器** 73 | 74 | 数据解析器。`json` `php` `swoole` `msgpack` 格式的数据解析的简单封装。 75 | 76 | - 独立包名 [toolkit/data-parser](https://github.com/php-toolkit/data-parser) 77 | - 在本仓库的 [libs/data-parser](libs/data-parser) 78 | 79 | **11. 额外的帮助类库** 80 | 81 | 额外的帮助类库。数据、日期、格式化等帮助类。 简单的 config,options,event,alias等traits收集整理 82 | 83 | - 独立包名 [toolkit/helper-utils](https://github.com/php-toolkit/helper-utils) 84 | - 在本仓库的 [libs/helper-utils](libs/helper-utils) 85 | 86 | ## 安装 87 | 88 | ```bash 89 | composer require toolkit/toolkit 90 | ``` 91 | 92 | ## 文档 93 | 94 | - classes docs https://php-toolkit.github.io/toolkit/classes-docs/master/ 95 | 96 | ## 开发 97 | 98 | ```bash 99 | composer install 100 | php toolkit dev -h 101 | ``` 102 | 103 | ### git subtree 104 | 105 | git subtree usage example: 106 | 107 | - add a lib repo 108 | 109 | ```bash 110 | git subtree add --prefix=libs/php-utils https://github.com/php-toolkit/php-utils master --squash 111 | ``` 112 | 113 | - update a lib repo 114 | 115 | ```bash 116 | git subtree pull --prefix=libs/php-utils https://github.com/php-toolkit/php-utils master --squash 117 | ``` 118 | 119 | - push a lib repo 120 | 121 | ```bash 122 | git subtree push --prefix=libs/php-utils https://github.com/php-toolkit/php-utils master 123 | ``` 124 | 125 | ## License 126 | 127 | MIT 128 | 129 | ## 我的其他项目 130 | 131 | - **`inhere/console`** 功能丰富的命令行应用,命令行工具库 132 | - git repo [github](https://github.com/inhere/php-console) [gitee](https://gitee.com/inhere/php-console) 133 | - **`inhere/php-validate`** 一个简洁小巧且功能完善的php验证库。仅有几个文件,无依赖。 134 | - git repo [github](https://github.com/inhere/php-validate) [gitee](https://gitee.com/inhere/php-validate) 135 | - **`inhere/sroute`** 轻量且快速的路由库 136 | - git repo [github](https://github.com/inhere/php-srouter) [gitee](https://gitee.com/inhere/php-srouter) 137 | - **`inhere/event-manager`** psr-14 的事件管理实现 138 | - git repo [github](https://github.com/inhere/php-event-manager) [gitee](https://gitee.com/inhere/php-event-manager) 139 | - **`inhere/middleware`** psr-15 HTTP中间件的实现 140 | - git repo [github](https://github.com/inhere/php-middleware) [gitee](https://gitee.com/inhere/php-middleware) 141 | 142 | 143 | > 更多请查看我的 [github](https://github.com/inhere) 144 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "toolkit/toolkit", 3 | "type": "library", 4 | "keywords": [ 5 | "php", 6 | "library", 7 | "tools" 8 | ], 9 | "homepage": "https://github.com/php-toolkit/toolkit", 10 | "description": "some useful library of the php", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "inhere", 15 | "email": "in.798@qq.com", 16 | "homepage": "http://www.yzone.net/" 17 | } 18 | ], 19 | "require": { 20 | "php": ">7.1.0", 21 | "psr/container": "^1.0", 22 | "toolkit/stdlib": "^1.0" 23 | }, 24 | "require-dev": { 25 | "inhere/console": "dev-master" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Toolkit\\Dev\\": "src/" 30 | } 31 | }, 32 | "suggest": { 33 | "inhere/php-validate": "Very lightweight data validate tool", 34 | "inhere/console": "a lightweight php console application library." 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # toolkit 2 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | libs/*/test 15 | 16 | 17 | 18 | 19 | 20 | libs/*/src 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /sami.doc.inc: -------------------------------------------------------------------------------- 1 | files() 9 | ->name('*.php') 10 | ->notName('routes.php') 11 | ->exclude(['test', 'example']) 12 | ->in([ 13 | __DIR__ . '/libs/' 14 | ]); 15 | 16 | $versions = GitVersionCollection::create(__DIR__); 17 | 18 | return new Sami($iterator, [ 19 | // 'theme' => 'enhanced', 20 | // 'versions' => $versions, 21 | 'title' => 'Php Toolkit Classes Documentation', 22 | 'build_dir' => __DIR__ . '/classes-docs/%version%', 23 | 'cache_dir' => __DIR__ . '/caches/%version%', 24 | 'default_opened_level' => 1, 25 | // 'store' => new MyArrayStore, 26 | ]); 27 | 28 | /** 29 | * usage: php sami.phar update --force sami.doc.inc 30 | */ 31 | -------------------------------------------------------------------------------- /src/autoload.php: -------------------------------------------------------------------------------- 1 | $lib . '/arr-utils/src', 7 | 'Toolkit\ArrUtilTest\\' => $lib . '/arr-utils/test', 8 | // cli-utils 9 | 'Toolkit\Cli\\' => $lib . '/cli-utils/src', 10 | 'Toolkit\CliTest\\' => $lib . '/cli-utils/test', 11 | // di 12 | 'Toolkit\DI\\' => $lib . '/di/src', 13 | 'Toolkit\DITest\\' => $lib . '/di/test', 14 | // collection 15 | 'Toolkit\CollectionTest\\' => $lib . '/collection/test', 16 | 'Toolkit\Collection\\' => $lib . '/collection/src', 17 | // file parse 18 | 'Toolkit\File\Parse\\' => $lib . '/file-parse/src', 19 | 'Toolkit\File\ParseTest\\' => $lib . '/file-parse/test', 20 | // file utils 21 | 'Toolkit\File\\' => $lib . '/file-utils/src', 22 | 'Toolkit\FileTest\\' => $lib . '/file-utils/test', 23 | // obj-utils 24 | 'Toolkit\ObjUtil\\' => $lib . '/obj-utils/src', 25 | 'Toolkit\ObjUtilTest\\' => $lib . '/obj-utils/test', 26 | // php utils 27 | 'Toolkit\PhpUtil\\' => $lib . '/php-utils/src', 28 | 'Toolkit\PhpUtilTest\\' => $lib . '/php-utils/test', 29 | // str utils 30 | 'Toolkit\StrUtil\\' => $lib . '/str-utils/src', 31 | 'Toolkit\StrUtilTest\\' => $lib . '/str-utils/test', 32 | // sys utils 33 | 'Toolkit\Sys\\' => $lib . '/sys-utils/src', 34 | 'Toolkit\SysTest\\' => $lib . '/sys-utils/test', 35 | ]; 36 | 37 | spl_autoload_register(function ($class) use ($map) { 38 | foreach ($map as $np => $dir) { 39 | if (0 === strpos($class, $np)) { 40 | $path = str_replace('\\', '/', substr($class, strlen($np))); 41 | $file = $dir . "/example/{$path}.php"; 42 | 43 | if ($file && is_file($file)) { 44 | include $file; 45 | return; 46 | } 47 | } 48 | } 49 | }); 50 | -------------------------------------------------------------------------------- /src/collection/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .phpintel/ 3 | !README.md 4 | !.gitkeep 5 | composer.lock 6 | *.swp 7 | *.log 8 | *.pid 9 | *.patch 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /src/collection/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 inhere 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/collection/README.md: -------------------------------------------------------------------------------- 1 | # data collection 2 | 3 | [![License](https://img.shields.io/packagist/l/toolkit/collection.svg?style=flat-square)](LICENSE) 4 | [![Php Version](https://img.shields.io/badge/php-%3E=7.1.0-brightgreen.svg?maxAge=2592000)](https://packagist.org/packages/toolkit/collection) 5 | [![Latest Stable Version](http://img.shields.io/packagist/v/toolkit/collection.svg)](https://packagist.org/packages/toolkit/collection) 6 | 7 | data collection utils for php 8 | 9 | - data collection 10 | - language manage 11 | 12 | ## Install 13 | 14 | ```bash 15 | composer require toolkit/collection 16 | ``` 17 | 18 | ## License 19 | 20 | MIT 21 | -------------------------------------------------------------------------------- /src/collection/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "toolkit/collection", 3 | "type": "library", 4 | "description": "some data collection tool library of the php", 5 | "keywords": [ 6 | "library", 7 | "tool", 8 | "php" 9 | ], 10 | "homepage": "https://github.com/php-toolkit/collection", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "inhere", 15 | "email": "in.798@qq.com", 16 | "homepage": "http://www.yzone.net/" 17 | } 18 | ], 19 | "require": { 20 | "php": ">7.1.0", 21 | "toolkit/arr-utils": "~1.0", 22 | "toolkit/str-utils": "~1.0", 23 | "toolkit/obj-utils": "~1.0", 24 | "toolkit/file-parse": "~1.0" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "Toolkit\\Collection\\": "src/" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/collection/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | test/ 15 | 16 | 17 | 18 | 19 | 20 | src 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/collection/src/ActiveData.php: -------------------------------------------------------------------------------- 1 | load($data, $recursive); 54 | } 55 | } 56 | 57 | /** 58 | * 初始化,载入数据 59 | * 60 | * @param array $data 61 | * @param bool $recursive 62 | * 63 | * @return $this 64 | */ 65 | public function load($data, bool $recursive = false): self 66 | { 67 | foreach ($data as $name => $value) { 68 | $name = trim($name); 69 | 70 | if (is_numeric($name)) { 71 | continue; 72 | } 73 | 74 | $this->$name = $recursive && is_array($value) ? static::create($value, $recursive) : $value; 75 | } 76 | 77 | return $this; 78 | } 79 | 80 | public function isStrict(): bool 81 | { 82 | return false; 83 | } 84 | 85 | /** 86 | * @param bool $toArray 87 | * 88 | * @return array|ArrayIterator 89 | * @throws ReflectionException 90 | */ 91 | public function all(bool $toArray = false) 92 | { 93 | $class = new ReflectionClass($this); 94 | $attrs = []; 95 | 96 | foreach ($class->getProperties() as $property) { 97 | if ($property->isPublic() && !$property->isStatic()) { 98 | $attrs[$property->getName()] = $property->getValue($this); 99 | } 100 | } 101 | 102 | //return $toArray ? $attrs : (new \ArrayObject($attrs)); 103 | return $toArray ? $attrs : new ArrayIterator($attrs); 104 | } 105 | 106 | /** 107 | * 以点连接 快速获取子级节点的值 108 | * 109 | * @param string $name 110 | * 111 | * @return ActiveData|mixed 112 | */ 113 | public function get(string $name) 114 | { 115 | if (strpos($name, '.')) { 116 | $names = explode('.', $name); 117 | $node = $this; 118 | 119 | foreach ($names as $n) { 120 | if ($node instanceof self && property_exists($node, $n)) { 121 | $node = $node->$n; 122 | } else { 123 | if ($this->isStrict()) { 124 | throw new RuntimeException("Stored data don't exists node '$n'"); 125 | } 126 | 127 | $node = null; 128 | break; 129 | } 130 | } 131 | 132 | return $node; 133 | } 134 | 135 | return property_exists($this, $name) ? $this->$name : null; 136 | } 137 | 138 | /** 139 | * Defined by IteratorAggregate interface 140 | * Returns an iterator for this object, for use with foreach 141 | * 142 | * @return ArrayIterator 143 | * @throws ReflectionException 144 | */ 145 | public function getIterator(): ArrayIterator 146 | { 147 | return $this->all(); 148 | } 149 | 150 | /** 151 | * Checks whether an offset exists in the iterator. 152 | * 153 | * @param mixed $offset The array offset. 154 | * 155 | * @return boolean True if the offset exists, false otherwise. 156 | */ 157 | public function offsetExists($offset): bool 158 | { 159 | return property_exists($this, $offset); 160 | } 161 | 162 | /** 163 | * Gets an offset in the iterator. 164 | * 165 | * @param mixed $offset The array offset. 166 | * 167 | * @return mixed The array value if it exists, null otherwise. 168 | */ 169 | public function offsetGet($offset) 170 | { 171 | return $this->$offset; 172 | } 173 | 174 | /** 175 | * Sets an offset in the iterator. 176 | * 177 | * @param mixed $offset The array offset. 178 | * @param mixed $value The array value. 179 | * 180 | * @return void 181 | */ 182 | public function offsetSet($offset, $value): void 183 | { 184 | $this->$offset = $value; 185 | } 186 | 187 | /** 188 | * Unset an offset in the iterator. 189 | * 190 | * @param mixed $offset The array offset. 191 | * 192 | * @return void 193 | */ 194 | public function offsetUnset($offset): void 195 | { 196 | unset($this->$offset); 197 | } 198 | 199 | public function __isset($name) 200 | { 201 | return $this->offsetExists($name); 202 | } 203 | 204 | public function __set($name, $value) 205 | { 206 | } 207 | 208 | public function __get($name) 209 | { 210 | return $this->get($name); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/collection/src/CollectionInterface.php: -------------------------------------------------------------------------------- 1 | format = $format; 73 | 74 | if (is_string($data) && is_dir($data)) { 75 | $this->mode = self::MODE_FOLDER; 76 | $this->folderPath = $data; 77 | $data = null; 78 | } 79 | 80 | if ($this->mode === self::MODE_FOLDER && !is_dir($this->folderPath)) { 81 | throw new InvalidArgumentException("Config mode is 'folder'. the property 'folderPath' must is a folder path!"); 82 | } 83 | 84 | parent::__construct($data, $this->format, $name); 85 | } 86 | 87 | /** 88 | * set config value by path 89 | * 90 | * @param string $path 91 | * @param mixed $value 92 | * 93 | * @return mixed 94 | * @throws InvalidArgumentException 95 | */ 96 | public function set($path, $value) 97 | { 98 | // if is readonly 99 | if ($this->readonly && $this->has($path)) { 100 | throw new InvalidArgumentException("Config data have been setting readonly. don't allow change."); 101 | } 102 | 103 | return parent::set($path, $value); 104 | } 105 | 106 | /** 107 | * get value by path 108 | * 109 | * @param string $path 110 | * @param string $default 111 | * 112 | * @return mixed 113 | * @throws InvalidArgumentException 114 | */ 115 | public function get(string $path, $default = null) 116 | { 117 | if ($this->mode === self::MODE_FOLDER) { 118 | $nodes = Str::toArray($path, $this->separator); 119 | $name = array_shift($nodes);// config file name 120 | 121 | // if config file not load. load it. 122 | if (!isset($this->data[$name])) { 123 | $file = $this->folderPath . "/{$name}.{$this->format}"; 124 | 125 | if (!is_file($file)) { 126 | throw new InvalidArgumentException("The want get config file not exist, Name: $name, File: $file"); 127 | } 128 | 129 | $this->data[$name] = self::read($file, $this->format); 130 | } 131 | } 132 | 133 | return parent::get($path, $default); 134 | } 135 | 136 | /** 137 | * get Mode 138 | * 139 | * @return string 140 | */ 141 | public function getMode(): string 142 | { 143 | return $this->mode; 144 | } 145 | 146 | /** 147 | * @param string $mode 148 | */ 149 | public function setMode(string $mode): void 150 | { 151 | $this->mode = $mode; 152 | } 153 | 154 | /** 155 | * @param bool $readonly 156 | */ 157 | public function setReadonly($readonly): void 158 | { 159 | $this->readonly = (bool)$readonly; 160 | } 161 | 162 | /** 163 | * data is Readonly 164 | * 165 | * @return boolean 166 | */ 167 | public function isReadonly(): bool 168 | { 169 | return $this->readonly; 170 | } 171 | 172 | /** 173 | * @return string 174 | */ 175 | public function getFormat(): string 176 | { 177 | return $this->format; 178 | } 179 | 180 | /** 181 | * @param string $format 182 | */ 183 | public function setFormat(string $format): void 184 | { 185 | $this->format = $format; 186 | } 187 | 188 | /** 189 | * @return string 190 | */ 191 | public function getFolderPath(): string 192 | { 193 | return $this->folderPath; 194 | } 195 | 196 | /** 197 | * @param string $folderPath 198 | * 199 | * @throws InvalidArgumentException 200 | */ 201 | public function setFolderPath(string $folderPath): void 202 | { 203 | if (!is_dir($folderPath)) { 204 | throw new InvalidArgumentException("The config files folder path is not exists! Path: $folderPath"); 205 | } 206 | 207 | $this->folderPath = $folderPath; 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/collection/src/JsonMessage.php: -------------------------------------------------------------------------------- 1 | 'success', 'code' => 23]); 19 | * $mg->data = [ 'key' => 'test']; 20 | * echo json_encode($mg); 21 | * response to client: 22 | * { 23 | * "code":23, 24 | * "msg":"success", 25 | * "data": { 26 | * "key":"value" 27 | * } 28 | * } 29 | */ 30 | class JsonMessage 31 | { 32 | /** 33 | * @var int 34 | */ 35 | public $code; 36 | 37 | /** 38 | * @var string 39 | */ 40 | public $msg; 41 | 42 | /** 43 | * @var int|float 44 | */ 45 | public $time; 46 | 47 | /** 48 | * @var array|string 49 | */ 50 | public $data; 51 | 52 | public static function make($data = null, $msg = 'success', $code = 0) 53 | { 54 | return new static($data, $msg, $code); 55 | } 56 | 57 | /** 58 | * JsonMessage constructor. 59 | * 60 | * @param null $data 61 | * @param string $msg 62 | * @param int $code 63 | */ 64 | public function __construct($data = null, $msg = 'success', $code = 0) 65 | { 66 | $this->data = $data; 67 | $this->msg = $msg; 68 | $this->code = $code; 69 | } 70 | 71 | /** 72 | * @return bool 73 | */ 74 | public function isSuccess(): bool 75 | { 76 | return (int)$this->code === 0; 77 | } 78 | 79 | /** 80 | * @return bool 81 | */ 82 | public function isFailure(): bool 83 | { 84 | return (int)$this->code !== 0; 85 | } 86 | 87 | /** 88 | * @param $code 89 | * 90 | * @return $this 91 | */ 92 | public function code($code): self 93 | { 94 | $this->code = (int)$code; 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * @param $msg 101 | * 102 | * @return $this 103 | */ 104 | public function msg($msg): self 105 | { 106 | $this->msg = $msg; 107 | 108 | return $this; 109 | } 110 | 111 | /** 112 | * @param string $key 113 | * @param mixed $value 114 | */ 115 | public function add($key, $value): void 116 | { 117 | if (null === $this->data) { 118 | $this->data = []; 119 | } 120 | 121 | $this->data[$key] = $value; 122 | } 123 | 124 | /** 125 | * @param array|string $data 126 | * 127 | * @return $this 128 | */ 129 | public function data($data): self 130 | { 131 | $this->data = $data; 132 | 133 | return $this; 134 | } 135 | 136 | /** 137 | * @return array 138 | */ 139 | public function all(): array 140 | { 141 | // add a new alert message 142 | return [ 143 | 'code' => (int)$this->code, 144 | 'msg' => $this->msg, 145 | 'data' => (array)$this->data 146 | ]; 147 | } 148 | 149 | /** 150 | * @return array 151 | */ 152 | public function toArray(): array 153 | { 154 | return $this->all(); 155 | } 156 | 157 | /** 158 | * @return string 159 | */ 160 | public function __toString() 161 | { 162 | return (string)json_encode($this->all()); 163 | } 164 | 165 | /** 166 | * @param string $name 167 | * 168 | * @return bool 169 | */ 170 | public function __isset(string $name) 171 | { 172 | return isset($this->data[$name]); 173 | } 174 | 175 | /** 176 | * @param string $name 177 | * @param $value 178 | */ 179 | public function __set(string $name, $value) 180 | { 181 | $this->data[$name] = $value; 182 | } 183 | 184 | /** 185 | * @param string $name 186 | * 187 | * @return mixed 188 | * @throws InvalidArgumentException 189 | */ 190 | public function __get($name) 191 | { 192 | if (isset($this->data[$name])) { 193 | return $this->data[$name]; 194 | } 195 | 196 | throw new InvalidArgumentException(sprintf('the property is not exists: %s', $name)); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/collection/src/LiteCollection.php: -------------------------------------------------------------------------------- 1 | replace($items); 41 | } 42 | 43 | /** 44 | * @param string $name 45 | * @param null|mixed $default 46 | * 47 | * @return mixed|null 48 | */ 49 | public function get(string $name, $default = null) 50 | { 51 | return $this[$name] ?? $default; 52 | } 53 | 54 | /** 55 | * @param string $name 56 | * @param mixed $value 57 | * 58 | * @return mixed|null 59 | */ 60 | public function add($name, $value) 61 | { 62 | if (isset($this[$name])) { 63 | return null; 64 | } 65 | 66 | $this[$name] = $value; 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * @param string $name 73 | * @param mixed $value 74 | * 75 | * @return mixed|null 76 | */ 77 | public function set($name, $value) 78 | { 79 | return $this[$name] = $value; 80 | } 81 | 82 | /** 83 | * @param array $items 84 | */ 85 | public function replace(array $items) 86 | { 87 | foreach ($items as $key => $value) { 88 | $this->set($key, $value); 89 | } 90 | } 91 | 92 | /** 93 | * @param callable $filter 94 | * 95 | * @return static 96 | */ 97 | public function reject(callable $filter) 98 | { 99 | $data = []; 100 | 101 | foreach ($this as $key => $value) { 102 | if (!$filter($value, $key)) { 103 | $data[$key] = $value; 104 | } 105 | 106 | unset($this[$key]); 107 | } 108 | 109 | return new static($data); 110 | } 111 | 112 | /** 113 | * @param callable $callback 114 | * 115 | * @return static 116 | */ 117 | public function map(callable $callback) 118 | { 119 | $data = []; 120 | 121 | foreach ($this as $key => $value) { 122 | $data[$key] = $callback($value, $key); 123 | unset($this[$key]); 124 | } 125 | 126 | return new static($data); 127 | } 128 | 129 | /** 130 | * @param string $char 131 | * 132 | * @return string 133 | */ 134 | public function implode($char = ','): string 135 | { 136 | // $string = ''; 137 | // 138 | // foreach ($this as $key => $value) { 139 | // $string .= is_array($value) ? $this->implode($char, $value) : implode($char, $value); 140 | // $string .= implode($char, $value); 141 | // } 142 | 143 | return implode($char, $this->all()); 144 | } 145 | 146 | /** 147 | * {@inheritDoc} 148 | */ 149 | public function all(): array 150 | { 151 | return $this->getArrayCopy(); 152 | } 153 | 154 | /** 155 | * {@inheritDoc} 156 | */ 157 | public function has(string $key): bool 158 | { 159 | return array_key_exists($key, $this->data); 160 | } 161 | 162 | /** 163 | * {@inheritDoc} 164 | */ 165 | public function remove($key) 166 | { 167 | if (isset($this[$key])) { 168 | $val = $this[$key]; 169 | unset($this[$key]); 170 | 171 | return $val; 172 | } 173 | 174 | return null; 175 | } 176 | 177 | /** 178 | * clear all data 179 | */ 180 | public function clear(): void 181 | { 182 | foreach ($this as $key) { 183 | unset($this[$key]); 184 | } 185 | } 186 | 187 | /** 188 | * Specify data which should be serialized to JSON 189 | * 190 | * @link http://php.net/manual/en/jsonserializable.jsonserialize.php 191 | * @return mixed data which can be serialized by json_encode, 192 | * which is a value of any type other than a resource. 193 | * @since 5.4.0 194 | */ 195 | public function jsonSerialize() 196 | { 197 | return $this->getArrayCopy(); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/collection/src/SimpleCollection.php: -------------------------------------------------------------------------------- 1 | replace($items); 42 | } 43 | 44 | public function __destruct() 45 | { 46 | $this->clear(); 47 | } 48 | 49 | /******************************************************************************** 50 | * Collection interface 51 | *******************************************************************************/ 52 | 53 | /** 54 | * Set collection item 55 | * 56 | * @param string $key The data key 57 | * @param mixed $value The data value 58 | * 59 | * @return $this 60 | */ 61 | public function set($key, $value) 62 | { 63 | $this->data[$key] = $value; 64 | 65 | return $this; 66 | } 67 | 68 | /** 69 | * @param $name 70 | * @param $value 71 | * 72 | * @return $this 73 | */ 74 | public function add($name, $value): self 75 | { 76 | if (!$this->has($name)) { 77 | $this->set($name, $value); 78 | } 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * Get collection item for key 85 | * 86 | * @param string $key The data key 87 | * @param mixed $default The default value to return if data key does not exist 88 | * 89 | * @return mixed The key's value, or the default value 90 | */ 91 | public function get(string $key, $default = null) 92 | { 93 | return $this->has($key) ? $this->data[$key] : $default; 94 | } 95 | 96 | /** 97 | * Add item to collection 98 | * 99 | * @param array $items Key-value array of data to append to this collection 100 | */ 101 | public function replace(array $items) 102 | { 103 | foreach ($items as $key => $value) { 104 | $this->set($key, $value); 105 | } 106 | } 107 | 108 | /** 109 | * @param array $names 110 | * 111 | * @return array 112 | */ 113 | public function gets(array $names): array 114 | { 115 | $values = []; 116 | 117 | foreach ($names as $name) { 118 | $values[] = $this->get($name); 119 | } 120 | 121 | return $values; 122 | } 123 | 124 | /** 125 | * @param array $data 126 | * 127 | * @return static 128 | */ 129 | public function sets(array $data) 130 | { 131 | foreach ($data as $key => $value) { 132 | $this->set($key, $value); 133 | } 134 | 135 | return $this; 136 | } 137 | 138 | /** 139 | * @param callable $filter 140 | * 141 | * @return static 142 | */ 143 | public function reject(callable $filter) 144 | { 145 | $data = []; 146 | 147 | foreach ($this as $key => $value) { 148 | if (!$filter($value, $key)) { 149 | $data[$key] = $value; 150 | } 151 | 152 | unset($this[$key]); 153 | } 154 | 155 | return new static($data); 156 | } 157 | 158 | /** 159 | * @param callable $callback 160 | * 161 | * @return static 162 | */ 163 | public function map(callable $callback) 164 | { 165 | $data = []; 166 | 167 | foreach ($this->getIterator() as $key => $value) { 168 | $data[$key] = $callback($value, $key); 169 | unset($this[$key]); 170 | } 171 | 172 | return new static($data); 173 | } 174 | 175 | /** 176 | * @param string $char 177 | * 178 | * @return string 179 | */ 180 | public function implode(string $char = ','): string 181 | { 182 | return implode($char, $this->all()); 183 | } 184 | 185 | /** 186 | * Get all items in collection 187 | * 188 | * @return array The collection's source data 189 | */ 190 | public function all(): array 191 | { 192 | return $this->data; 193 | } 194 | 195 | /** 196 | * @return array 197 | */ 198 | public function toArray(): array 199 | { 200 | return $this->all(); 201 | } 202 | 203 | /** 204 | * Get collection keys 205 | * 206 | * @return array The collection's source data keys 207 | */ 208 | public function keys(): array 209 | { 210 | return array_keys($this->data); 211 | } 212 | 213 | /** 214 | * Does this collection have a given key? 215 | * 216 | * @param string $key The data key 217 | * 218 | * @return bool 219 | */ 220 | public function has(string $key): bool 221 | { 222 | return array_key_exists($key, $this->data); 223 | } 224 | 225 | /** 226 | * Remove item from collection 227 | * 228 | * @param string $key The data key 229 | * 230 | * @return mixed|null 231 | */ 232 | public function remove($key) 233 | { 234 | $value = null; 235 | 236 | if ($this->has($key)) { 237 | $value = $this->data[$key]; 238 | unset($this->data[$key]); 239 | } 240 | 241 | return $value; 242 | } 243 | 244 | /** 245 | * Remove all items from collection 246 | */ 247 | public function clear(): void 248 | { 249 | $this->data = []; 250 | } 251 | 252 | /******************************************************************************** 253 | * ArrayAccess interface 254 | *******************************************************************************/ 255 | 256 | /** 257 | * Does this collection have a given key? 258 | * 259 | * @param string $key The data key 260 | * 261 | * @return bool 262 | */ 263 | public function offsetExists($key): bool 264 | { 265 | return $this->has($key); 266 | } 267 | 268 | /** 269 | * Get collection item for key 270 | * 271 | * @param string $key The data key 272 | * 273 | * @return mixed The key's value, or the default value 274 | */ 275 | public function offsetGet($key) 276 | { 277 | return $this->get($key); 278 | } 279 | 280 | /** 281 | * Set collection item 282 | * 283 | * @param string $key The data key 284 | * @param mixed $value The data value 285 | */ 286 | public function offsetSet($key, $value) 287 | { 288 | $this->set($key, $value); 289 | } 290 | 291 | /** 292 | * Remove item from collection 293 | * 294 | * @param string $key The data key 295 | * 296 | * @return mixed|null 297 | */ 298 | public function offsetUnset($key) 299 | { 300 | return $this->remove($key); 301 | } 302 | 303 | /******************************************************************************** 304 | * Countable interface 305 | *******************************************************************************/ 306 | 307 | /** 308 | * Get number of items in collection 309 | * 310 | * @return int 311 | */ 312 | public function count(): int 313 | { 314 | return count($this->data); 315 | } 316 | 317 | /******************************************************************************** 318 | * JsonSerializable interface 319 | *******************************************************************************/ 320 | 321 | /** 322 | * @return array 323 | */ 324 | public function jsonSerialize(): array 325 | { 326 | return $this->data; 327 | } 328 | 329 | /******************************************************************************** 330 | * Serializable interface 331 | *******************************************************************************/ 332 | 333 | /** 334 | * @return string 335 | */ 336 | public function serialize(): string 337 | { 338 | return serialize($this->data); 339 | } 340 | 341 | /** 342 | * @param string $serialized 343 | * @param bool|array $allowedClasses 344 | */ 345 | public function unserialize($serialized, $allowedClasses = false) 346 | { 347 | $this->data = unserialize($serialized, ['allowed_classes' => $allowedClasses]); 348 | } 349 | 350 | /******************************************************************************** 351 | * IteratorAggregate interface 352 | *******************************************************************************/ 353 | 354 | /** 355 | * Get collection iterator 356 | * 357 | * @return ArrayIterator 358 | */ 359 | public function getIterator(): Traversable 360 | { 361 | return new ArrayIterator($this->data); 362 | } 363 | 364 | /******************************************************************************** 365 | * Magic method 366 | ******************************************************************************/ 367 | 368 | /** 369 | * @param $name 370 | * 371 | * @return mixed 372 | */ 373 | public function __get($name) 374 | { 375 | return $this->get($name); 376 | } 377 | 378 | public function __set($name, $value) 379 | { 380 | return $this->set($name, $value); 381 | } 382 | 383 | public function __isset($name) 384 | { 385 | return $this->has($name); 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /src/collection/test/LanguageTest.php: -------------------------------------------------------------------------------- 1 | 'en', 27 | 'allowed' => ['en', 'zh-CN'], 28 | 'basePath' => __DIR__ . '/testdata', 29 | 'langFiles' => [ 30 | 'response.php' 31 | ], 32 | ]); 33 | 34 | $arr = [ 35 | 0 => 'a', 36 | 1 => 'b', 37 | 'k' => 'c', 38 | ]; 39 | 40 | 41 | $msg = $l->tl('response.key'); 42 | $this->assertEquals('message', $msg); 43 | $this->assertTrue($l->has('response.key')); 44 | $this->assertEquals('successful', $l->trans('response.0')); 45 | $this->assertEquals('error', $l->trans('response.2')); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/collection/test/boot.php: -------------------------------------------------------------------------------- 1 | 'successful', 11 | 2 => 'error', 12 | 'key' => 'message', 13 | ]; 14 | -------------------------------------------------------------------------------- /src/collection/test/testdata/zh-CN/response.php: -------------------------------------------------------------------------------- 1 | '操作成功', 12 | 2 => '发生错误', 13 | 'key' => '消息', 14 | ]; 15 | -------------------------------------------------------------------------------- /src/data-parser/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .phpintel/ 3 | !README.md 4 | !.gitkeep 5 | composer.lock 6 | *.swp 7 | *.log 8 | *.pid 9 | *.patch 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /src/data-parser/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 inhere 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/data-parser/README.md: -------------------------------------------------------------------------------- 1 | # data parser utils 2 | 3 | simple data parser for php 4 | 5 | driver 6 | 7 | - json(by `json_encode`) 8 | - php(by `serialize`) 9 | - swoole(by extension `swoole_serialize`) 10 | - msgpack(by extension `msgpack`) 11 | 12 | ## Install 13 | 14 | - composer command 15 | 16 | ```bash 17 | composer require toolkit/data-parser 18 | ``` 19 | 20 | ## Usage 21 | 22 | ```php 23 | $parser = new SwooleParser(); 24 | // $parser = new JsonParser(); 25 | // $parser = new PhpParser(); 26 | // $parser = new MsgPackParser(); 27 | 28 | // encode 29 | $encoded = $parser->encode($data); 30 | 31 | // decode 32 | $decoded = $parser->encode($encoded); 33 | ``` 34 | 35 | ## Unit testing 36 | 37 | ```bash 38 | phpunit 39 | ``` 40 | 41 | ## License 42 | 43 | MIT 44 | -------------------------------------------------------------------------------- /src/data-parser/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "toolkit/data-parser", 3 | "type": "library", 4 | "description": "some data parser tool library of the php", 5 | "keywords": [ 6 | "library", 7 | "tool", 8 | "php" 9 | ], 10 | "homepage": "https://github.com/php-toolkit/data-parser", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "inhere", 15 | "email": "in.798@qq.com", 16 | "homepage": "http://www.yzone.net/" 17 | } 18 | ], 19 | "require": { 20 | "php": ">7.1.0" 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "Toolkit\\DataParser\\": "src/" 25 | } 26 | }, 27 | "suggest": { 28 | "inhere/php-validate": "Very lightweight data validate tool", 29 | "inhere/console": "a lightweight php console application library." 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/data-parser/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | test/ 16 | 17 | 18 | 19 | 20 | 21 | src 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/data-parser/src/AbstractDataParser.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | abstract class AbstractDataParser implements DataParserInterface 18 | { 19 | /** 20 | * @var array 21 | */ 22 | protected $encodeOpts; 23 | 24 | /** 25 | * @var array 26 | */ 27 | protected $decodeOpts; 28 | 29 | /** 30 | * JsonParser constructor. 31 | * 32 | * @param array $encodeOpts 33 | * @param array $decodeOpts 34 | */ 35 | public function __construct(array $encodeOpts = [], array $decodeOpts = []) 36 | { 37 | $this->encodeOpts = $encodeOpts; 38 | $this->decodeOpts = $decodeOpts; 39 | } 40 | 41 | /** 42 | * @return array 43 | */ 44 | public function getEncodeOpts(): array 45 | { 46 | return $this->encodeOpts; 47 | } 48 | 49 | /** 50 | * @return array 51 | */ 52 | public function getDecodeOpts(): array 53 | { 54 | return $this->decodeOpts; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/data-parser/src/DataParserAwareTrait.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | trait DataParserAwareTrait 18 | { 19 | /** 20 | * @var DataParserInterface 21 | */ 22 | private $parser; 23 | 24 | /** 25 | * @return DataParserInterface 26 | */ 27 | public function getParser(): DataParserInterface 28 | { 29 | if (!$this->parser) { 30 | $this->parser = new PhpParser(); 31 | } 32 | 33 | return $this->parser; 34 | } 35 | 36 | /** 37 | * @param DataParserInterface $parser 38 | * 39 | * @return DataParserAwareTrait 40 | */ 41 | public function setParser(DataParserInterface $parser): self 42 | { 43 | $this->parser = $parser; 44 | 45 | return $this; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/data-parser/src/DataParserInterface.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | interface DataParserInterface 18 | { 19 | /** 20 | * @param mixed $data 21 | * 22 | * @return string 23 | */ 24 | public function encode($data): string; 25 | 26 | /** 27 | * @param string $data 28 | * 29 | * @return mixed 30 | */ 31 | public function decode(string $data); 32 | } 33 | -------------------------------------------------------------------------------- /src/data-parser/src/JsonParser.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | class JsonParser extends AbstractDataParser 21 | { 22 | /** 23 | * class constructor. 24 | * 25 | * @param array $encodeOpts 26 | * @param array $decodeOpts 27 | */ 28 | public function __construct(array $encodeOpts = [], array $decodeOpts = []) 29 | { 30 | parent::__construct($encodeOpts, $decodeOpts ?: [true]); 31 | } 32 | 33 | /** 34 | * @param mixed $data 35 | * 36 | * @return string 37 | */ 38 | public function encode($data): string 39 | { 40 | return json_encode($data, ...$this->encodeOpts); 41 | } 42 | 43 | /** 44 | * @param string $data 45 | * 46 | * @return mixed 47 | */ 48 | public function decode(string $data) 49 | { 50 | return json_decode($data, ...$this->decodeOpts); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/data-parser/src/MsgPackParser.php: -------------------------------------------------------------------------------- 1 | 21 | * @link https://github.com/msgpack/msgpack-php php-ext 22 | * @link https://github.com/rybakit/msgpack.php php 23 | */ 24 | class MsgPackParser extends AbstractDataParser 25 | { 26 | /** 27 | * class constructor. 28 | * 29 | * @throws RuntimeException 30 | */ 31 | public function __construct() 32 | { 33 | if (!function_exists('msgpack_pack')) { 34 | throw new RuntimeException("The php extension 'msgpack' is required!"); 35 | } 36 | 37 | parent::__construct(); 38 | } 39 | 40 | /** 41 | * @param mixed $data 42 | * 43 | * @return string 44 | */ 45 | public function encode($data): string 46 | { 47 | return msgpack_pack($data); 48 | } 49 | 50 | /** 51 | * @param string $data 52 | * 53 | * @return mixed 54 | */ 55 | public function decode(string $data) 56 | { 57 | return msgpack_unpack($data); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/data-parser/src/PhpParser.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | class PhpParser implements DataParserInterface 21 | { 22 | /** 23 | * @param mixed $data 24 | * 25 | * @return string 26 | */ 27 | public function encode($data): string 28 | { 29 | return serialize($data); 30 | } 31 | 32 | /** 33 | * @param string $data 34 | * 35 | * @return mixed 36 | */ 37 | public function decode(string $data) 38 | { 39 | return unserialize($data, ['allowed_classes' => false]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/data-parser/src/SwooleParser.php: -------------------------------------------------------------------------------- 1 | 20 | * @link https://wiki.swoole.com/wiki/page/p-serialize.html 21 | */ 22 | class SwooleParser extends AbstractDataParser 23 | { 24 | /** 25 | * class constructor. 26 | * 27 | * @param array $encodeOpts 28 | * 29 | * @throws RuntimeException 30 | */ 31 | public function __construct(array $encodeOpts = []) 32 | { 33 | if (!class_exists(Serialize::class, false)) { 34 | throw new RuntimeException("The php extension 'swoole_serialize' is required!"); 35 | } 36 | 37 | parent::__construct($encodeOpts); 38 | } 39 | 40 | /** 41 | * @param mixed $data 42 | * 43 | * @return string 44 | */ 45 | public function encode($data): string 46 | { 47 | return (string)Serialize::pack($data, ...$this->encodeOpts); 48 | } 49 | 50 | /** 51 | * @param string $data 52 | * 53 | * @return mixed 54 | */ 55 | public function decode(string $data) 56 | { 57 | return Serialize::unpack($data, ...$this->decodeOpts); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/data-parser/test/JsonParserTest.php: -------------------------------------------------------------------------------- 1 | decode($str); 27 | 28 | $this->assertArrayHasKey('name', $ret); 29 | } 30 | 31 | public function testEncode(): void 32 | { 33 | $data = [ 34 | 'name' => 'value', 35 | ]; 36 | 37 | $parser = new JsonParser(); 38 | $ret = $parser->encode($data); 39 | 40 | $this->assertJson($ret); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/data-parser/test/PhpParserTest.php: -------------------------------------------------------------------------------- 1 | decode($str); 27 | 28 | $this->assertIsArray($ret); 29 | $this->assertArrayHasKey('name', $ret); 30 | } 31 | 32 | public function testEncode(): void 33 | { 34 | $data = [ 35 | 'name' => 'value', 36 | ]; 37 | 38 | $parser = new PhpParser(); 39 | $ret = $parser->encode($data); 40 | 41 | $this->assertIsString($ret); 42 | $this->assertStringStartsWith('a:1:{', $ret); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/data-parser/test/boot.php: -------------------------------------------------------------------------------- 1 | 'className', 39 | // 2. 类的静态方法, 参数($definition[0])则传入对应方法 className::staticMethod(args...) 40 | 'class' => 'className::staticMethod', 41 | // 3. 类的动态方法, 参数($definition[0]) 则传入对应方法 (new className)->method(args...) 42 | 'class' => 'className->method', 43 | 44 | // 设置参数方式, 没有key 45 | [ 46 | arg1,arg2,arg3,... 47 | ] 48 | 49 | // 设置属性 , // prop1 prop2 prop3 将会被收集 作为属性 50 | prop1 => value1, 51 | prop2 => value2, 52 | ... ... 53 | 54 | // 一些服务设置(别名,是否共享). 将会合并到最后一个参数中 55 | '_options' => [...] 56 | ] 57 | ``` 58 | 59 | - object: 60 | 61 | ```php 62 | $definition = new xxClass(); 63 | ``` 64 | 65 | - closure: 66 | 67 | ```php 68 | $definition = function($di){ 69 | return object; 70 | }; 71 | ``` 72 | 73 | #### 选项 74 | 75 | - array `$opts` 选项 76 | 77 | ```php 78 | [ 79 | 'shared' => (bool), 是否共享,单例 80 | 'locked' => (bool), 是否锁定服务 81 | 'aliases' => (array), 别名 82 | 'init' => (bool), 立即初始化 83 | ] 84 | ``` 85 | 86 | ## License 87 | 88 | MIT 89 | -------------------------------------------------------------------------------- /src/di/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "toolkit/di", 3 | "type": "library", 4 | "description": "some di tool library of the php", 5 | "keywords": [ 6 | "library", 7 | "tool", 8 | "php" 9 | ], 10 | "homepage": "https://github.com/php-toolkit/di", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "inhere", 15 | "email": "in.798@qq.com", 16 | "homepage": "http://www.yzone.net/" 17 | } 18 | ], 19 | "require": { 20 | "php": ">7.1.0", 21 | "toolkit/obj-utils": "^1.0", 22 | "psr/container": "^1.0" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "Toolkit\\DI\\": "src/" 27 | } 28 | }, 29 | "suggest": { 30 | "inhere/php-validate": "Very lightweight data validate tool", 31 | "inhere/console": "a lightweight php console application library." 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/di/example/di.php: -------------------------------------------------------------------------------- 1 | LiteLogger::make(['name' => 'test']), 16 | 'logger2' => [ 17 | 'target' => LiteLogger::class . '::make', 18 | ['name' => 'test2']// first arg 19 | ] 20 | ]); 21 | 22 | var_dump($di); 23 | 24 | var_dump($di->get('logger2')); 25 | -------------------------------------------------------------------------------- /src/di/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | test/ 15 | 16 | 17 | 18 | 19 | 20 | src 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/di/src/CallableResolver.php: -------------------------------------------------------------------------------- 1 | container = $container; 37 | } 38 | 39 | /** 40 | * Resolve toResolve into a closure that that the router can dispatch. 41 | * 42 | * If toResolve is of the format 'class:method', then try to extract 'class' 43 | * from the container otherwise instantiate it and then dispatch 'method'. 44 | * 45 | * @param mixed $toResolve 46 | * 47 | * @return callable 48 | * 49 | * @throws RuntimeException if the callable does not exist 50 | * @throws RuntimeException if the callable is not resolvable 51 | */ 52 | public function resolve($toResolve): callable 53 | { 54 | if (is_callable($toResolve)) { 55 | return $toResolve; 56 | } 57 | 58 | if (!is_string($toResolve)) { 59 | $this->assertCallable($toResolve); 60 | } 61 | 62 | // check for slim callable as "class:method" 63 | if (preg_match(self::CALLABLE_PATTERN, $toResolve, $matches)) { 64 | $resolved = $this->resolveCallable($matches[1], $matches[2]); 65 | $this->assertCallable($resolved); 66 | 67 | return $resolved; 68 | } 69 | 70 | $resolved = $this->resolveCallable($toResolve); 71 | $this->assertCallable($resolved); 72 | 73 | return $resolved; 74 | } 75 | 76 | /** 77 | * Check if string is something in the DIC 78 | * that's callable or is a class name which has an __invoke() method. 79 | * 80 | * @param string $class 81 | * @param string $method 82 | * 83 | * @return callable 84 | * 85 | * @throws InvalidArgumentException 86 | * @throws RuntimeException if the callable does not exist 87 | */ 88 | private function resolveCallable($class, $method = '__invoke'): callable 89 | { 90 | if ($cb = $this->container->getIfExist($class)) { 91 | return [$cb, $method]; 92 | } 93 | 94 | if (!class_exists($class)) { 95 | throw new RuntimeException(sprintf('Callable %s does not exist', $class)); 96 | } 97 | 98 | return [new $class($this->container), $method]; 99 | } 100 | 101 | /** 102 | * @param Callable $callable 103 | * 104 | * @throws RuntimeException if the callable is not resolvable 105 | */ 106 | private function assertCallable($callable): void 107 | { 108 | if (!is_callable($callable)) { 109 | throw new RuntimeException(sprintf('%s is not resolvable', 110 | is_array($callable) || is_object($callable) ? json_encode($callable) : $callable)); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/di/src/CallableResolverAwareTrait.php: -------------------------------------------------------------------------------- 1 | container instanceof ContainerInterface) { 40 | return $callable; 41 | } 42 | 43 | /** @var CallableResolverInterface $resolver */ 44 | $resolver = $this->container->get('callableResolver'); 45 | 46 | return $resolver->resolve($callable); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/di/src/DIManager.php: -------------------------------------------------------------------------------- 1 | [ 31 | 'root' => null,// 'container name'=> a base Container instance 32 | 'children' => [] 33 | ] 34 | ]; 35 | 36 | /** 37 | * @return Container 38 | */ 39 | public static function getDefault(): Container 40 | { 41 | return self::make('root', self::$defaultGroup); 42 | } 43 | 44 | /** 45 | * @param null|string $name 46 | * 47 | * @return Container 48 | */ 49 | public static function getContainer(string $name = null): Container 50 | { 51 | return self::make($name); 52 | } 53 | 54 | /** 55 | * @param string $name 56 | * @param string $group 57 | * 58 | * @return Container 59 | */ 60 | public static function make(string $name = null, string $group = null): Container 61 | { 62 | $group = $group ?: self::$defaultGroup; 63 | 64 | // No name, return default's base container. 65 | if (!$name) { 66 | if (empty(self::$containers[$group]['root'])) { 67 | $container = new Container; 68 | $container->name = 'di.root'; 69 | 70 | self::$containers[$group]['root'] = $container; 71 | } 72 | 73 | return self::$containers[$group]['root']; 74 | } 75 | 76 | // Has name, we return children container. 77 | if (empty(self::$containers[$group][$name]) || !(self::$containers[$group][$name] instanceof Container)) { 78 | self::$containers[$group][$name] = new Container([], self::make(null, $group)); 79 | self::$containers[$group][$name]->name = $name; 80 | } 81 | 82 | return self::$containers[$group][$name]; 83 | } 84 | 85 | /** 86 | * setProfile 87 | * 88 | * @param string $group 89 | * 90 | * @return void 91 | */ 92 | public static function setDefaultGroup($group = 'di'): void 93 | { 94 | $group = strtolower(trim($group)); 95 | 96 | if (!isset(static::$containers[$group])) { 97 | static::$containers[$group] = [ 98 | 'root' => null, 99 | 'children' => [] 100 | ]; 101 | } 102 | 103 | static::$defaultGroup = $group; 104 | } 105 | 106 | /** 107 | * Method to get property Profile 108 | * 109 | * @return string 110 | */ 111 | public static function getDefaultGroup(): string 112 | { 113 | return static::$defaultGroup; 114 | } 115 | 116 | /** 117 | * reset 118 | * 119 | * @param string $group 120 | */ 121 | public static function reset($group = null): void 122 | { 123 | if (!$group) { 124 | static::$containers = []; 125 | } else { 126 | static::$containers[$group] = []; 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/di/src/Exception/DependencyResolutionException.php: -------------------------------------------------------------------------------- 1 | 'id', 27 | * 'alias name2' => 'id' 28 | * ] 29 | */ 30 | private $aliases = []; 31 | 32 | /** 33 | * set name alias 34 | * 35 | * @param string $name 36 | * @param array|string $alias 37 | */ 38 | public function setAlias(string $name, $alias): void 39 | { 40 | if (!$name || !$alias) { 41 | return; 42 | } 43 | 44 | // setting 45 | if (is_array($alias)) { 46 | foreach ($alias as $aliasName) { 47 | if (!isset($this->aliases[$aliasName])) { 48 | $this->aliases[$aliasName] = $name; 49 | } 50 | } 51 | } else { 52 | $this->aliases[$alias] = $name; 53 | } 54 | } 55 | 56 | /** 57 | * @param string $alias 58 | * 59 | * @return mixed 60 | */ 61 | public function resolveAlias(string $alias): string 62 | { 63 | return $this->aliases[$alias] ?? $alias; 64 | } 65 | 66 | /** 67 | * @param $alias 68 | * 69 | * @return bool 70 | */ 71 | public function isAlias(string $alias): bool 72 | { 73 | return isset($this->aliases[$alias]); 74 | } 75 | 76 | /** 77 | * @return array 78 | */ 79 | public function getAliases(): array 80 | { 81 | return $this->aliases; 82 | } 83 | 84 | /** 85 | * @param array $aliases 86 | * 87 | * @return $this 88 | */ 89 | public function setAliases(array $aliases): self 90 | { 91 | $this->aliases = $aliases; 92 | 93 | return $this; 94 | } 95 | 96 | /** 97 | * @param array $aliases 98 | * 99 | * @return $this 100 | */ 101 | public function addAliases(array $aliases): self 102 | { 103 | $this->aliases = array_merge($this->aliases, $aliases); 104 | 105 | return $this; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/di/src/ObjectItem.php: -------------------------------------------------------------------------------- 1 | arguments = $arguments; 63 | 64 | $this->shared = (bool)$shared; 65 | $this->locked = (bool)$locked; 66 | 67 | $this->setCallback($callback); 68 | } 69 | 70 | /** 71 | * __clone 72 | */ 73 | private function __clone() 74 | { 75 | } 76 | 77 | /** 78 | * __destruct 79 | */ 80 | public function __destruct() 81 | { 82 | $this->instance = $this->callback = $this->arguments = null; 83 | } 84 | 85 | /** 86 | * @param Container $container 87 | * @param bool $forceNew 88 | * 89 | * @return mixed|null 90 | */ 91 | public function get(Container $container, $forceNew = false) 92 | { 93 | if ($this->shared) { 94 | if (!$this->instance || $forceNew) { 95 | $cb = $this->callback; 96 | $this->instance = $cb($container); 97 | } 98 | 99 | // 激活后就锁定,不允许再覆盖设置服务 100 | $this->locked = true; 101 | return $this->instance; 102 | } 103 | 104 | $cb = $this->callback; 105 | 106 | return $cb($container); 107 | } 108 | 109 | /** 110 | * @return mixed 111 | */ 112 | public function getCallback() 113 | { 114 | return $this->callback; 115 | } 116 | 117 | /** 118 | * @param $callback 119 | */ 120 | public function setCallback($callback): void 121 | { 122 | if (!method_exists($callback, '__invoke')) { 123 | $this->instance = $callback; 124 | $callback = function () use ($callback) { 125 | return $callback; 126 | }; 127 | } 128 | 129 | $this->callback = $callback; 130 | } 131 | 132 | /** 133 | * @return array 134 | */ 135 | public function getArguments(): array 136 | { 137 | return $this->arguments; 138 | } 139 | 140 | /** 141 | * 给服务设置参数,在获取服务实例前 142 | * 143 | * @param array $params 设置参数 144 | * 145 | * @throws InvalidArgumentException 146 | */ 147 | public function setArguments(array $params): void 148 | { 149 | $this->arguments = $params; 150 | } 151 | 152 | /** 153 | * @return mixed 154 | */ 155 | public function getInstance() 156 | { 157 | return $this->instance; 158 | } 159 | 160 | /** 161 | * @return bool 162 | */ 163 | public function isLocked(): bool 164 | { 165 | return $this->locked; 166 | } 167 | 168 | /** 169 | * @param bool $locked 170 | */ 171 | public function setLocked($locked = true): void 172 | { 173 | $this->locked = (bool)$locked; 174 | } 175 | 176 | /** 177 | * @return bool 178 | */ 179 | public function isShared(): bool 180 | { 181 | return $this->shared; 182 | } 183 | 184 | /** 185 | * @param bool $shared 186 | */ 187 | public function setShared($shared = true): void 188 | { 189 | $this->shared = (bool)$shared; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/di/src/ServiceProviderInterface.php: -------------------------------------------------------------------------------- 1 | SomeClass::class, 26 | 's2' => [ 27 | 'class' => MakeByStatic::class . '::factory', 28 | [ 29 | [ 30 | 'name' => 'test2' 31 | ] 32 | ] 33 | ], 34 | 's3' => [ 35 | 'class' => MakeByMethod::class . '->factory', 36 | [ 37 | [ 38 | 'name' => 'test2' 39 | ] 40 | ] 41 | ] 42 | ]); 43 | 44 | $this->assertCount(3, $di); 45 | $this->assertTrue($di->has('s1')); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/di/test/MakeByMethod.php: -------------------------------------------------------------------------------- 1 | options = $options; 26 | } 27 | 28 | /** 29 | * @return array 30 | */ 31 | public function getOptions(): array 32 | { 33 | return $this->options; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/di/test/boot.php: -------------------------------------------------------------------------------- 1 | 7.1.0", 21 | "toolkit/arr-utils": "~1.0", 22 | "toolkit/obj-utils": "~1.0", 23 | "toolkit/str-utils": "~1.0", 24 | "toolkit/sys-utils": "~1.0", 25 | "toolkit/file-utils": "~1.0", 26 | "toolkit/php-utils": "~1.0" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "Toolkit\\Util\\": "src/Util", 31 | "Toolkit\\Traits\\": "src/Traits", 32 | "Toolkit\\Helper\\": "src/Helper" 33 | } 34 | }, 35 | "suggest": { 36 | "inhere/php-validate": "Very lightweight data validate tool", 37 | "inhere/console": "a lightweight php console application library." 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/helper-utils/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | test 16 | 17 | 18 | 19 | 20 | 21 | src 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/helper-utils/src/Helper/AssertHelper.php: -------------------------------------------------------------------------------- 1 | $allowedClasses]); 37 | } 38 | 39 | /** 40 | * php对象转换成为数组 41 | * @param iterable|array|\Traversable $data 42 | * @param bool $recursive 43 | * @return array|bool 44 | */ 45 | public static function toArray($data, $recursive = false) 46 | { 47 | // Ensure the input data is an array. 48 | if (\is_object($data)) { 49 | if ($data instanceof \Traversable) { 50 | $data = iterator_to_array($data); 51 | } elseif (method_exists($data, 'toArray')) { 52 | $data = $data->toArray(); 53 | } 54 | } else { 55 | $data = (array)$data; 56 | } 57 | 58 | if ($recursive) { 59 | foreach ($data as &$value) { 60 | if (\is_array($value) || \is_object($value)) { 61 | $value = static::toArray($value, $recursive); 62 | } 63 | } 64 | } 65 | 66 | return $data; 67 | } 68 | 69 | /** 70 | * data to array 71 | * @param array|\Traversable $array 72 | * @param string $class 73 | * @return mixed 74 | */ 75 | public static function toObject($array, $class = \stdClass::class) 76 | { 77 | $object = new $class; 78 | 79 | foreach ($array as $name => $value) { 80 | $name = trim($name); 81 | 82 | if (!$name || is_numeric($name)) { 83 | continue; 84 | } 85 | 86 | $object->$name = \is_array($value) ? self::toObject($value) : $value; 87 | } 88 | 89 | return $object; 90 | } 91 | 92 | /** 93 | * Sanitize a string 94 | * @param string $string String to sanitize 95 | * @param bool $clearTag clear html tag 96 | * @return string Sanitized string 97 | */ 98 | public static function safeOutput($string, $clearTag = false): string 99 | { 100 | if (!$clearTag) { 101 | $string = strip_tags($string); 102 | } 103 | 104 | return @self::htmlentitiesUTF8($string); 105 | } 106 | 107 | /** 108 | * @param $string 109 | * @param int $type 110 | * @return array|string 111 | */ 112 | public static function htmlentitiesUTF8($string, $type = ENT_QUOTES) 113 | { 114 | if (\is_array($string)) { 115 | return array_map([__CLASS__, 'htmlentitiesUTF8'], $string); 116 | } 117 | 118 | return htmlentities((string)$string, $type, 'utf-8'); 119 | } 120 | 121 | /** 122 | * @param $string 123 | * @return string 124 | */ 125 | public static function htmlentitiesDecodeUTF8($string): string 126 | { 127 | if (\is_array($string)) { 128 | $string = array_map([__CLASS__, 'htmlentitiesDecodeUTF8'], $string); 129 | 130 | return (string)array_shift($string); 131 | } 132 | 133 | return html_entity_decode((string)$string, ENT_QUOTES, 'utf-8'); 134 | } 135 | 136 | /** 137 | * @param $argc 138 | * @param $argv 139 | * @return null 140 | */ 141 | public static function argvToGET($argc, $argv) 142 | { 143 | if ($argc <= 1) { 144 | return true; 145 | } 146 | 147 | // get the first argument and parse it like a query string 148 | parse_str($argv[1], $args); 149 | if (!\is_array($args) || !\count($args)) { 150 | return true; 151 | } 152 | 153 | $_GET = array_merge($args, $_GET); 154 | $_SERVER['QUERY_STRING'] = $argv[1]; 155 | 156 | return true; 157 | } 158 | 159 | /** 160 | * 清理数据的空白 161 | * @param $data array|string 162 | * @return array|string 163 | */ 164 | public static function trim($data) 165 | { 166 | if (is_scalar($data)) { 167 | return trim($data); 168 | } 169 | 170 | array_walk_recursive($data, function (&$value) { 171 | $value = trim($value); 172 | }); 173 | 174 | return $data; 175 | } 176 | 177 | /* 178 | * strip_tags — 从字符串中去除 HTML 和 PHP 标记 179 | * 由于 strip_tags() 无法实际验证 HTML,不完整或者破损标签将导致更多的数据被删除。 180 | * $allow_tags 允许的标记,多个以空格隔开 181 | **/ 182 | public static function stripTags($data, $allow_tags = null) 183 | { 184 | if (\is_array($data)) { 185 | foreach ($data as $k => $v) { 186 | $data[$k] = self::stripTags($v, $allow_tags); 187 | } 188 | 189 | return $data; 190 | } 191 | 192 | if (\is_string($data) || is_numeric($data)) { 193 | return strip_tags($data, $allow_tags); 194 | } 195 | 196 | return false; 197 | } 198 | 199 | /** 200 | * 对数组或字符串进行加斜杠\转义处理 去除转义 201 | * 去除转义返回一个去除反斜线后的字符串(\' 转换为 ' 等等)。双反斜线(\\)被转换为单个反斜线(\)。 202 | * @param array|string $data 数据可以是字符串或数组 203 | * @param int $escape 进行转义 true 转义处理 false 去除转义 204 | * @param int $level 增强 205 | * @return array|string 206 | */ 207 | public static function slashes($data, $escape = 1, $level = 0) 208 | { 209 | if (\is_array($data)) { 210 | foreach ((array)$data as $key => $value) { 211 | $data[$key] = self::slashes($value, $escape, $level); 212 | } 213 | 214 | return $data; 215 | } 216 | 217 | $data = trim($data); 218 | 219 | if (!$escape) { 220 | return stripslashes($data); 221 | } 222 | 223 | $data = addslashes($data); 224 | 225 | if ($level) { 226 | // 两个str_replace替换转义目的是防止黑客转换SQL编码进行攻击。 227 | $data = str_replace(['_', '%'], ["\_", "\%"], $data); // 转义掉_ % 228 | } 229 | 230 | return $data; 231 | } 232 | 233 | public static function escape_query($str): string 234 | { 235 | return strtr($str, [ 236 | "\0" => '', 237 | "'" => ''', 238 | '"' => '"', 239 | "\\" => '\', 240 | // more secure 241 | '<' => '<', 242 | '>' => '>', 243 | ]); 244 | } 245 | 246 | /** 247 | * 对数据进行字符集转换处理,数据可以是字符串或数组及对象 248 | * @param array|string $data 249 | * @param $in_charset 250 | * @param $out_charset 251 | * @return array|string 252 | */ 253 | public static function changeEncode($data, $in_charset = 'GBK', $out_charset = 'UTF-8') 254 | { 255 | if (\is_array($data)) { 256 | 257 | foreach ($data as $key => $value) { 258 | $data[$key] = self::changeEncode($value, $in_charset, $out_charset); 259 | } 260 | 261 | return $data; 262 | } 263 | 264 | if (\function_exists('mb_convert_encoding')) { 265 | return mb_convert_encoding($data, $out_charset, $in_charset); 266 | } 267 | 268 | return iconv($in_charset, $out_charset . '/' . '/IGNORE', $data); 269 | } 270 | 271 | } 272 | -------------------------------------------------------------------------------- /src/helper-utils/src/Helper/DateHelper.php: -------------------------------------------------------------------------------- 1 | static::getOption('host', 'localhost'), 84 | '{PORT}' => static::getOption('port', 3306), 85 | '{DBNAME}' => static::getOption('database'), 86 | '{CHARSET}' => static::getOption('charset', 'utf8') 87 | ] 88 | ]; 89 | } 90 | 91 | /** 92 | * cubrid 93 | * @return array 94 | */ 95 | protected static function cubrid(): array 96 | { 97 | return [ 98 | 'cubrid:host={HOST};port={PORT};dbname={DBNAME}', 99 | [ 100 | '{HOST}' => static::getOption('host', 'localhost'), 101 | '{PORT}' => static::getOption('port', 33000), 102 | '{DBNAME}' => static::getOption('database') 103 | ] 104 | ]; 105 | } 106 | 107 | /** 108 | * dblib 109 | * @return array 110 | */ 111 | protected static function dblib(): array 112 | { 113 | return [ 114 | 'dblib:host={HOST};port={PORT};dbname={DBNAME}', 115 | [ 116 | '{HOST}' => static::getOption('host', 'localhost'), 117 | '{PORT}' => static::getOption('port', 1433), 118 | '{DBNAME}' => static::getOption('database') 119 | ] 120 | ]; 121 | } 122 | 123 | /** 124 | * firebird 125 | * @return array 126 | */ 127 | protected static function firebird(): array 128 | { 129 | return [ 130 | 'firebird:dbname={DBNAME}', 131 | [ 132 | '{DBNAME}' => static::getOption('database') 133 | ] 134 | ]; 135 | } 136 | 137 | /** 138 | * ibm 139 | * @return array 140 | */ 141 | protected static function ibm(): array 142 | { 143 | if ($dsn = static::getOption('dsn')) { 144 | return [ 145 | 'ibm:DSN={DSN}', 146 | [ 147 | '{DSN}' => $dsn 148 | ] 149 | ]; 150 | } 151 | 152 | return [ 153 | 'ibm:hostname={HOST};port={PORT};database={DBNAME}', 154 | [ 155 | '{HOST}' => static::getOption('host', 'localhost'), 156 | '{PORT}' => static::getOption('port', 56789), 157 | '{DBNAME}' => static::getOption('database') 158 | ] 159 | ]; 160 | } 161 | 162 | /** 163 | * dblib 164 | * @return array 165 | */ 166 | protected static function informix(): array 167 | { 168 | if ($dsn = static::getOption('dsn')) { 169 | return [ 170 | 'informix:DSN={DSN}', 171 | [ 172 | '{DSN}' => $dsn 173 | ] 174 | ]; 175 | } 176 | 177 | return [ 178 | 'informix:host={HOST};service={PORT};database={DBNAME};server={SERVER};protocol={PROTOCOL}', 179 | [ 180 | '{HOST}' => static::getOption('host', 'localhost'), 181 | '{PORT}' => static::getOption('port', 1526), 182 | '{DBNAME}' => static::getOption('database'), 183 | '{SERVER}' => static::getOption('server'), 184 | '{PROTOCOL}' => static::getOption('protocol') 185 | ] 186 | ]; 187 | } 188 | 189 | /** 190 | * mssql 191 | * @return array 192 | */ 193 | protected static function mssql(): array 194 | { 195 | return [ 196 | 'mssql:host={HOST};port={PORT};dbname={DBNAME}', 197 | [ 198 | '{HOST}' => static::getOption('host', 'localhost'), 199 | '{PORT}' => static::getOption('port', 1433), 200 | '{DBNAME}' => static::getOption('database') 201 | ] 202 | ]; 203 | } 204 | 205 | /** 206 | * oci 207 | * @return array 208 | */ 209 | protected static function oci(): array 210 | { 211 | if ($dsn = static::getOption('dsn')) { 212 | return [ 213 | 'oci:dbname={DSN};charset={CHARSET}', 214 | [ 215 | '{DSN}' => $dsn, 216 | '{CHARSET}' => static::getOption('charset', 'AL32UTF8') 217 | ] 218 | ]; 219 | } 220 | 221 | return [ 222 | 'oci:dbname=//#HOST#:#PORT#/#DBNAME};charset={CHARSET}', 223 | [ 224 | '{HOST}' => static::getOption('host', 'localhost'), 225 | '{PORT}' => static::getOption('port', 56789), 226 | '{DBNAME}' => static::getOption('database'), 227 | '{CHARSET}' => static::getOption('charset', 'AL32UTF8') 228 | ] 229 | ]; 230 | } 231 | 232 | /** 233 | * odbc 234 | * @return array 235 | */ 236 | protected static function odbc(): array 237 | { 238 | return [ 239 | 'odbc:DSN={DSN};UID:#USER};PWD={PASSWORD}', 240 | [ 241 | '{HOST}' => static::getOption('host', 'localhost'), 242 | '{USER}' => static::getOption('user', 1433), 243 | '{PASSWORD}' => static::getOption('password') 244 | ] 245 | ]; 246 | } 247 | 248 | /** 249 | * pgsql 250 | * @return array 251 | */ 252 | protected static function pgsql(): array 253 | { 254 | return [ 255 | 'pgsql:host={HOST};port={PORT};dbname={DBNAME}', 256 | [ 257 | '{HOST}' => static::getOption('host', 'localhost'), 258 | '{PORT}' => static::getOption('port', 5432), 259 | '{DBNAME}' => static::getOption('database', 'postgres') 260 | ] 261 | ]; 262 | } 263 | 264 | /** 265 | * Alias of pgsql 266 | * @return array 267 | */ 268 | protected static function postgresql(): array 269 | { 270 | return static::pgsql(); 271 | } 272 | 273 | /** 274 | * sqlite 275 | * @return array 276 | */ 277 | protected static function sqlite(): array 278 | { 279 | $version = (int)static::getOption('version'); 280 | 281 | $format = $version === 2 ? 'sqlite2:{DBNAME}' : 'sqlite:{DBNAME}'; 282 | 283 | return [ 284 | $format, 285 | [ 286 | '{DBNAME}' => static::getOption('database') 287 | ] 288 | ]; 289 | } 290 | 291 | /** 292 | * sybase 293 | * @return array 294 | */ 295 | protected static function sybase(): array 296 | { 297 | return [ 298 | 'pgsql:host={HOST};port={PORT};dbname={DBNAME}', 299 | [ 300 | '{HOST}' => static::getOption('host', 'localhost'), 301 | '{PORT}' => static::getOption('port', 1433), 302 | '{DBNAME}' => static::getOption('database') 303 | ] 304 | ]; 305 | } 306 | 307 | /** 308 | * sybase 309 | * @return array 310 | */ 311 | protected static function fourd(): array 312 | { 313 | return [ 314 | '4D:host={HOST};charset=UTF-8', 315 | [ 316 | '{HOST}' => static::getOption('host', 'localhost'), 317 | '{CHARSET}' => static::getOption('charset', 'UTF-8') 318 | ] 319 | ]; 320 | } 321 | 322 | /** 323 | * getOption 324 | * @param string $name 325 | * @param string $default 326 | * @return mixed 327 | */ 328 | protected static function getOption($name, $default = null) 329 | { 330 | return self::$options[$name] ?? $default; 331 | } 332 | } 333 | 334 | -------------------------------------------------------------------------------- /src/helper-utils/src/Helper/FormatHelper.php: -------------------------------------------------------------------------------- 1 | $format) { 38 | if ($secs >= $format[0]) { 39 | if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0]) 40 | || $index === \count($timeFormats) - 1 41 | ) { 42 | if (2 === \count($format)) { 43 | return $format[1]; 44 | } 45 | 46 | return floor($secs / $format[2]) . ' ' . $format[1]; 47 | } 48 | } 49 | } 50 | 51 | return date('Y-m-d H:i:s', $secs); 52 | } 53 | 54 | /** 55 | * @param string $mTime value is microtime(1) 56 | * @return string 57 | */ 58 | public static function microTime($mTime = null): string 59 | { 60 | if (!$mTime) { 61 | $mTime = microtime(true); 62 | } 63 | 64 | [$ts, $ms] = explode('.', sprintf('%.4f', $mTime)); 65 | 66 | return date('Y/m/d H:i:s', $ts) . '.' . $ms; 67 | } 68 | 69 | /** 70 | * @param $memory 71 | * @return string 72 | * ``` 73 | * Helper::memory(memory_get_usage(true)); 74 | * ``` 75 | */ 76 | public static function memory($memory): string 77 | { 78 | if ($memory >= 1024 * 1024 * 1024) { 79 | return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); 80 | } 81 | 82 | if ($memory >= 1024 * 1024) { 83 | return sprintf('%.1f MiB', $memory / 1024 / 1024); 84 | } 85 | 86 | if ($memory >= 1024) { 87 | return sprintf('%d KiB', $memory / 1024); 88 | } 89 | 90 | return sprintf('%d B', $memory); 91 | } 92 | 93 | /** 94 | * @param int $size 95 | * @return string 96 | * ``` 97 | * Helper::size(memory_get_usage(true)); 98 | * ``` 99 | */ 100 | public static function size(int $size): string 101 | { 102 | if ($size >= 1024 * 1024 * 1024) { 103 | return sprintf('%.1f Gb', $size / 1024 / 1024 / 1024); 104 | } 105 | 106 | if ($size >= 1024 * 1024) { 107 | return sprintf('%.1f Mb', $size / 1024 / 1024); 108 | } 109 | 110 | if ($size >= 1024) { 111 | return sprintf('%d Kb', $size / 1024); 112 | } 113 | 114 | return sprintf('%d b', $size); 115 | } 116 | 117 | /** 118 | * Format a number into a human readable format 119 | * e.g. 24962496 => 23.81M 120 | * @param $size 121 | * @param int $precision 122 | * @return string 123 | */ 124 | public static function bytes($size, $precision = 2): string 125 | { 126 | if (!$size) { 127 | return '0'; 128 | } 129 | 130 | $base = log($size) / log(1024); 131 | $suffixes = ['b', 'k', 'M', 'G', 'T']; 132 | $floorBase = floor($base); 133 | 134 | return round(1024 ** ($base - $floorBase), $precision) . $suffixes[(int)$floorBase]; 135 | } 136 | 137 | /** 138 | * Convert a shorthand byte value from a PHP configuration directive to an integer value 139 | * @param string $value value to convert 140 | * @return int 141 | */ 142 | public static function convertBytes($value): int 143 | { 144 | if (is_numeric($value)) { 145 | return $value; 146 | } 147 | 148 | $value_length = \strlen($value); 149 | $qty = (int)substr($value, 0, $value_length - 1); 150 | $unit = \strtolower(\substr($value, $value_length - 1)); 151 | switch ($unit) { 152 | case 'k': 153 | $qty *= 1024; 154 | break; 155 | case 'm': 156 | $qty *= 1048576; 157 | break; 158 | case 'g': 159 | $qty *= 1073741824; 160 | break; 161 | } 162 | 163 | return $qty; 164 | } 165 | 166 | /** 167 | * Replaces & with & for XHTML compliance 168 | * @param string $text Text to process 169 | * @return string Processed string. 170 | */ 171 | public static function ampReplace($text): string 172 | { 173 | $text = str_replace([ 174 | '&&', 175 | '&#', 176 | '&#', 177 | '&', 178 | '*-*', 179 | '*--*', 180 | ], [ 181 | '*--*', 182 | '*-*', 183 | '*-*', 184 | '&', 185 | '&#', 186 | '&&', 187 | ], $text); 188 | 189 | $text = (string)preg_replace('/|&(?![\w]+;)|/', '&', $text); 190 | 191 | return $text; 192 | } 193 | 194 | /** 195 | * Cleans text of all formatting and scripting code 196 | * @param string|null|array $text Text to clean 197 | * @return string Cleaned text. 198 | */ 199 | public static function cleanText(string $text): string 200 | { 201 | $text = preg_replace('/]*>.*?/si', '', $text); 202 | $text = preg_replace('/]*>([^<]+)<\/a>/is', '\2 (\1)', $text); 203 | $text = preg_replace('//', '', $text); 204 | $text = preg_replace('/{.+?}/', '', $text); 205 | $text = preg_replace('/ /', ' ', $text); 206 | $text = preg_replace('/&/', ' ', $text); 207 | $text = preg_replace('/"/', ' ', $text); 208 | $text = strip_tags($text); 209 | $text = htmlspecialchars($text); 210 | 211 | return $text; 212 | } 213 | 214 | /** 215 | * 返回删除注释和空格后的PHP源码(php_strip_whitespace) 216 | * @link http://cn2.php.net/manual/zh/function.php-strip-whitespace.php 217 | * @param string|bool $src 218 | * @return string 219 | */ 220 | public static function phpCode(string $src): string 221 | { 222 | // Whitespaces left and right from this signs can be ignored 223 | static $IW = [ 224 | T_CONCAT_EQUAL, // .= 225 | T_DOUBLE_ARROW, // => 226 | T_BOOLEAN_AND, // && 227 | T_BOOLEAN_OR, // || 228 | T_IS_EQUAL, // == 229 | T_IS_NOT_EQUAL, // != or <> 230 | T_IS_SMALLER_OR_EQUAL, // <= 231 | T_IS_GREATER_OR_EQUAL, // >= 232 | T_INC, // ++ 233 | T_DEC, // -- 234 | T_PLUS_EQUAL, // += 235 | T_MINUS_EQUAL, // -= 236 | T_MUL_EQUAL, // *= 237 | T_DIV_EQUAL, // /= 238 | T_IS_IDENTICAL, // === 239 | T_IS_NOT_IDENTICAL, // !== 240 | T_DOUBLE_COLON, // :: 241 | T_PAAMAYIM_NEKUDOTAYIM, // :: 242 | T_OBJECT_OPERATOR, // -> 243 | T_DOLLAR_OPEN_CURLY_BRACES, // ${ 244 | T_AND_EQUAL, // &= 245 | T_MOD_EQUAL, // %= 246 | T_XOR_EQUAL, // ^= 247 | T_OR_EQUAL, // |= 248 | T_SL, // << 249 | T_SR, // >> 250 | T_SL_EQUAL, // <<= 251 | T_SR_EQUAL, // >>= 252 | ]; 253 | 254 | if (!$src) { 255 | return false; 256 | } 257 | 258 | if (is_file($src) && (!$src = file_get_contents($src))) { 259 | return false; 260 | } 261 | 262 | $tokens = token_get_all($src); 263 | 264 | $new = ''; 265 | $c = \count($tokens); 266 | $iw = false; // ignore whitespace 267 | $ih = false; // in HEREDOC 268 | $ls = ''; // last sign 269 | $ot = null; // open tag 270 | for ($i = 0; $i < $c; $i++) { 271 | $token = $tokens[$i]; 272 | if (\is_array($token)) { 273 | [$tn, $ts] = $token; // tokens: number, string, line 274 | $tname = token_name($tn); 275 | if ($tn === T_INLINE_HTML) { 276 | $new .= $ts; 277 | $iw = false; 278 | } elseif ($tn === T_OPEN_TAG) { 279 | if (strpos($ts, ' ') || strpos($ts, "\n") || strpos($ts, "\t") || strpos($ts, "\r")) { 280 | $ts = rtrim($ts); 281 | } 282 | $ts .= ' '; 283 | $new .= $ts; 284 | $ot = T_OPEN_TAG; 285 | $iw = true; 286 | } elseif ($tn === T_OPEN_TAG_WITH_ECHO) { 287 | $new .= $ts; 288 | $ot = T_OPEN_TAG_WITH_ECHO; 289 | $iw = true; 290 | } elseif ($tn === T_CLOSE_TAG) { 291 | if ($ot === T_OPEN_TAG_WITH_ECHO) { 292 | $new = rtrim($new, '; '); 293 | } else { 294 | $ts = ' ' . $ts; 295 | } 296 | $new .= $ts; 297 | $ot = null; 298 | $iw = false; 299 | } elseif (\in_array($tn, $IW, true)) { 300 | $new .= $ts; 301 | $iw = true; 302 | } elseif ($tn === T_CONSTANT_ENCAPSED_STRING || $tn === T_ENCAPSED_AND_WHITESPACE) { 303 | if ($ts[0] === '"') { 304 | $ts = addcslashes($ts, "\n\t\r"); 305 | } 306 | $new .= $ts; 307 | $iw = true; 308 | } elseif ($tn === T_WHITESPACE) { 309 | $nt = @$tokens[$i + 1]; 310 | if (!$iw && (!\is_string($nt) || $nt === '$') && !\in_array($nt[0], $IW, true)) { 311 | $new .= ' '; 312 | } 313 | $iw = false; 314 | } elseif ($tn === T_START_HEREDOC) { 315 | $new .= "<< 4096, 31 | 'addContentLengthHeader' => false, 32 | ], $options); 33 | 34 | // Send response 35 | if (!headers_sent()) { 36 | // Status 37 | header(sprintf( 38 | 'HTTP/%s %s %s', 39 | $response->getProtocolVersion(), 40 | $response->getStatusCode(), 41 | $response->getReasonPhrase() 42 | )); 43 | 44 | // Headers 45 | foreach ($response->getHeaders() as $name => $values) { 46 | /** @var array $values */ 47 | foreach ($values as $value) { 48 | header(sprintf('%s: %s', $name, $value), false); 49 | } 50 | } 51 | } 52 | 53 | // Body 54 | if (!self::isEmptyResponse($response)) { 55 | $body = $response->getBody(); 56 | if ($body->isSeekable()) { 57 | $body->rewind(); 58 | } 59 | 60 | $chunkSize = $options['chunkSize']; 61 | $contentLength = $response->getHeaderLine('Content-Length'); 62 | 63 | if (!$contentLength) { 64 | $contentLength = $body->getSize(); 65 | } 66 | 67 | if (null !== $contentLength) { 68 | $amountToRead = $contentLength; 69 | while ($amountToRead > 0 && !$body->eof()) { 70 | $data = $body->read(min($chunkSize, $amountToRead)); 71 | echo $data; 72 | $amountToRead -= \strlen($data); 73 | 74 | if (connection_status() !== CONNECTION_NORMAL) { 75 | break; 76 | } 77 | } 78 | } else { 79 | while (!$body->eof()) { 80 | echo $body->read($chunkSize); 81 | if (connection_status() !== CONNECTION_NORMAL) { 82 | break; 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * Helper method, which returns true if the provided response must not output a body and false 91 | * if the response could have a body. 92 | * @see https://tools.ietf.org/html/rfc7231 93 | * @param ResponseInterface $response 94 | * @return bool 95 | */ 96 | public static function isEmptyResponse(ResponseInterface $response): bool 97 | { 98 | if (method_exists($response, 'isEmpty')) { 99 | return $response->isEmpty(); 100 | } 101 | 102 | return \in_array($response->getStatusCode(), [204, 205, 304], true); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/helper-utils/src/Helper/IntHelper.php: -------------------------------------------------------------------------------- 1 | $country_name, 47 | 'stateOrProvinceName' => $state_or_province_name, 48 | 'localityName' => $locality_name, 49 | 'organizationName' => $organization_name, 50 | 'organizationalUnitName' => $organizational_unit_name, 51 | 'commonName' => $common_name, 52 | 'emailAddress' => $email_address, 53 | ]; 54 | 55 | // private key 56 | $priKey = openssl_pkey_new(); 57 | $cert = openssl_csr_new($dn, $priKey); 58 | $cert = openssl_csr_sign($cert, null, $priKey, 365); 59 | 60 | $pem = []; 61 | 62 | openssl_x509_export($cert, $pem[0]); 63 | openssl_pkey_export($priKey, $pem[1], $pem_passphrase); 64 | 65 | $pem = implode($pem); 66 | 67 | return false !== file_put_contents($pem_file, $pem); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/helper-utils/src/Helper/UtilHelper.php: -------------------------------------------------------------------------------- 1 | console.' . $type . '(' . $data . ');'; 27 | } 28 | 29 | /** 30 | * @param string $pathname 31 | * @param int|string $projectId This must be a one character 32 | * @return int|string 33 | * @throws \LogicException 34 | */ 35 | public static function ftok($pathname, $projectId) 36 | { 37 | if (\strlen($projectId) > 1) { 38 | throw new \LogicException("the project id must be a one character(int/str). Input: $projectId"); 39 | } 40 | 41 | if (\function_exists('ftok')) { 42 | return ftok($pathname, $projectId); 43 | } 44 | 45 | if (!$st = @stat($pathname)) { 46 | return -1; 47 | } 48 | 49 | $key = sprintf('%u', ($st['ino'] & 0xffff) | (($st['dev'] & 0xff) << 16) | (($projectId & 0xff) << 24)); 50 | 51 | return $key; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/AopProxyAwareTrait.php: -------------------------------------------------------------------------------- 1 | [handler0, handler1], 21 | * 'XyzClass::methodAfter' => [handler2, handler3], 22 | * ] 23 | */ 24 | trait AopProxyAwareTrait 25 | { 26 | /** 27 | * @var array 28 | */ 29 | private static $proxyPoints = ['before', 'after']; 30 | 31 | /** 32 | * @var mixed the proxy target is a class name or a object 33 | */ 34 | private $proxyTarget; 35 | 36 | public function proxy($class, string $method = '', array $args = []) 37 | { 38 | $this->proxyTarget = $class; 39 | 40 | if ($method) { 41 | return $this->call($method, $args); 42 | } 43 | 44 | return $this; 45 | } 46 | 47 | /** 48 | * @param string $method 49 | * @param array $args 50 | * @return mixed 51 | * @throws \LogicException 52 | */ 53 | public function call(string $method, array $args = []) 54 | { 55 | if (!$target = $this->proxyTarget) { 56 | throw new \LogicException('Please setting the proxy target [proxyTarget]'); 57 | } 58 | 59 | // on before exec method 60 | if ($cbList = $this->findProxyCallback($target, $method)) { 61 | foreach ($cbList as $cb) { 62 | PhpHelper::call($cb, $target, $method, $args); 63 | } 64 | } 65 | 66 | // exec method 67 | $ret = PhpHelper::call([$target, $method], ...$args); 68 | 69 | // on after exec method 70 | if ($cb = $this->findProxyCallback($target, $method, 'after')) { 71 | foreach ($cbList as $cb) { 72 | PhpHelper::call($cb, $target, $method, $args); 73 | } 74 | } 75 | 76 | // clear 77 | $this->proxyTarget = null; 78 | 79 | return $ret; 80 | } 81 | 82 | /** 83 | * @param string $method 84 | * @param array $args 85 | * @return mixed 86 | */ 87 | public function __call(string $method, array $args = []) 88 | { 89 | return $this->call($method, $args); 90 | } 91 | 92 | /** 93 | * @param array ...$args 94 | * @return $this|mixed 95 | * @throws \InvalidArgumentException 96 | */ 97 | public function __invoke(...$args) 98 | { 99 | $num = \count($args); 100 | 101 | // only a object 102 | if ($num === 1) { 103 | return $this->proxy($args[0]); 104 | } 105 | 106 | // has object and method 107 | if ($num > 1) { 108 | $class = \array_shift($args); 109 | $method = \array_shift($args); 110 | 111 | return $this->proxy($class, $method, $args); 112 | } 113 | 114 | throw new \InvalidArgumentException('Missing parameters!'); 115 | } 116 | 117 | /** 118 | * @param string|object $target 119 | * @param string $method 120 | * @param string $prefix 121 | * @return array 122 | */ 123 | protected function findProxyCallback($target, $method, $prefix = 'before'): array: ?array 124 | { 125 | $className = \is_string($target) ? $target : \get_class($target); 126 | 127 | // e.g XyzClass::methodAfter 128 | $key = $className . '::' . $method . \ucfirst($prefix); 129 | 130 | return $this->proxyMap[$key] ?? []; 131 | } 132 | 133 | /** 134 | * @see addProxy() 135 | * @param $key 136 | * @param $handler 137 | * @param string $position 138 | * @return $this 139 | */ 140 | public function register($key, $handler, $position = 'before'): self 141 | { 142 | return $this->addProxy($key, $handler, $position); 143 | } 144 | 145 | /** 146 | * @param string $key eg 'XyzClass::method' 147 | * @param callable $handler 148 | * @param string $position 'before' 'after' 149 | * @return $this 150 | */ 151 | public function addProxy(string $key, $handler, string $position = 'before'): self 152 | { 153 | if (!\in_array($position, self::$proxyPoints, true)) { 154 | return $this; 155 | } 156 | 157 | $key .= \ucfirst($position); 158 | // save 159 | $this->proxyMap[$key][] = $handler; 160 | 161 | return $this; 162 | } 163 | 164 | /** 165 | * @param array $map 166 | * @return $this 167 | */ 168 | public function addProxies(array $map): self 169 | { 170 | foreach ($map as $key => $handler) { 171 | $position = 'before'; 172 | 173 | if (\is_array($handler)) { 174 | if (!isset($handler['handler'])) { 175 | continue; 176 | } 177 | 178 | $position = $handler['position'] ?? 'before'; 179 | $handler = $handler['handler']; 180 | } 181 | 182 | $this->addProxy($key, $handler, $position); 183 | } 184 | 185 | return $this; 186 | } 187 | 188 | /** 189 | * @return array 190 | */ 191 | public static function getProxyPoints(): array 192 | { 193 | return self::$proxyPoints; 194 | } 195 | 196 | /** 197 | * @return mixed 198 | */ 199 | public function getProxyTarget() 200 | { 201 | return $this->proxyTarget; 202 | } 203 | 204 | /** 205 | * @return array 206 | */ 207 | public function getProxyMap(): array 208 | { 209 | return $this->proxyMap; 210 | } 211 | 212 | /** 213 | * @param array $proxyMap 214 | */ 215 | public function setProxyMap(array $proxyMap): void: void 216 | { 217 | $this->proxyMap = $proxyMap; 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/Config/ConfigTrait.php: -------------------------------------------------------------------------------- 1 | config); 29 | } 30 | 31 | /** 32 | * Method to get property Options 33 | * @param string $name 34 | * @param mixed $default 35 | * @return mixed 36 | */ 37 | public function getValue(string $name, $default = null) 38 | { 39 | $value = Arr::getByPath($this->config, $name, $default); 40 | 41 | if ($value && $value instanceof \Closure) { 42 | $value = $value(); 43 | } 44 | 45 | return $value; 46 | } 47 | 48 | /** 49 | * Method to set property config 50 | * @param string $name 51 | * @param mixed $value 52 | * @return static Return self to support chaining. 53 | */ 54 | public function setValue($name, $value) 55 | { 56 | $this->config[$name] = $value; 57 | 58 | return $this; 59 | } 60 | 61 | /** 62 | * delete a option 63 | * @param $name 64 | * @return mixed|null 65 | */ 66 | public function delValue($name) 67 | { 68 | $value = null; 69 | 70 | if ($this->hasConfig($name)) { 71 | $value = $this->getValue($name); 72 | 73 | unset($this->config[$name]); 74 | } 75 | 76 | return $value; 77 | } 78 | 79 | /** 80 | * Method to get property Options 81 | * @param string|null $key 82 | * @return array 83 | */ 84 | public function getConfig(string $key = null): array 85 | { 86 | if ($key) { 87 | return $this->getValue($key); 88 | } 89 | 90 | return $this->config; 91 | } 92 | 93 | /** 94 | * Method to set property config 95 | * @param array $config 96 | * @param bool $loopMerge 97 | * @return static Return self to support chaining. 98 | */ 99 | public function setConfig(array $config, $loopMerge = true) 100 | { 101 | $this->config = $loopMerge ? Arr::merge($this->config, $config) : $config; 102 | 103 | return $this; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/Config/LiteConfigTrait.php: -------------------------------------------------------------------------------- 1 | config); 27 | } 28 | 29 | /** 30 | * Method to get property Options 31 | * @param string $name 32 | * @param mixed $default 33 | * @return mixed 34 | */ 35 | public function getValue($name, $default = null) 36 | { 37 | $value = array_key_exists($name, $this->config) ? $this->config[$name] : $default; 38 | 39 | if ($value && ($value instanceof \Closure)) { 40 | $value = $value(); 41 | } 42 | 43 | return $value; 44 | } 45 | 46 | /** 47 | * Method to set property config 48 | * @param string $name 49 | * @param mixed $value 50 | * @return static Return self to support chaining. 51 | */ 52 | public function setValue($name, $value) 53 | { 54 | $this->config[$name] = $value; 55 | 56 | return $this; 57 | } 58 | 59 | /** 60 | * delete a option 61 | * @param $name 62 | * @return mixed|null 63 | */ 64 | public function delValue($name) 65 | { 66 | $value = null; 67 | 68 | if ($this->hasConfig($name)) { 69 | $value = $this->getValue($name); 70 | 71 | unset($this->config[$name]); 72 | } 73 | 74 | return $value; 75 | } 76 | 77 | /** 78 | * Method to get property Options 79 | * @param string|null $key 80 | * @return array 81 | */ 82 | public function getConfig($key = null): array 83 | { 84 | if ($key) { 85 | return $this->getValue($key); 86 | } 87 | 88 | return $this->config; 89 | } 90 | 91 | /** 92 | * Method to set property config 93 | * @param array $config 94 | * @param bool $merge 95 | * @return static Return self to support chaining. 96 | */ 97 | public function setConfig(array $config, $merge = true) 98 | { 99 | $this->config = $merge ? array_merge($this->config, $config) : $config; 100 | 101 | return $this; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/Config/LiteOptionsTrait.php: -------------------------------------------------------------------------------- 1 | options); 27 | } 28 | 29 | /** 30 | * Method to get property Options 31 | * @param string $name 32 | * @param mixed $default 33 | * @return mixed 34 | */ 35 | public function getOption(string $name, $default = null) 36 | { 37 | $value = array_key_exists($name, $this->options) ? $this->options[$name] : $default; 38 | 39 | if ($value && ($value instanceof \Closure)) { 40 | $value = $value(); 41 | } 42 | 43 | return $value; 44 | } 45 | 46 | /** 47 | * Method to set property options 48 | * @param string $name 49 | * @param mixed $value 50 | * @return static Return self to support chaining. 51 | */ 52 | public function setOption($name, $value) 53 | { 54 | $this->options[$name] = $value; 55 | 56 | return $this; 57 | } 58 | 59 | /** 60 | * delete a option 61 | * @param $name 62 | * @return mixed|null 63 | */ 64 | public function delOption($name) 65 | { 66 | $value = null; 67 | 68 | if ($this->hasOption($name)) { 69 | $value = $this->getOption($name); 70 | 71 | unset($this->options[$name]); 72 | } 73 | 74 | return $value; 75 | } 76 | 77 | /** 78 | * Method to get property Options 79 | * @return array 80 | */ 81 | public function getOptions(): array 82 | { 83 | return $this->options; 84 | } 85 | 86 | /** 87 | * Method to set property options 88 | * @param array $options 89 | * @param bool $merge 90 | * @return static Return self to support chaining. 91 | */ 92 | public function setOptions(array $options, $merge = true) 93 | { 94 | $this->options = $merge ? array_merge($this->options, $options) : $options; 95 | 96 | return $this; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/Config/OptionsTrait.php: -------------------------------------------------------------------------------- 1 | options); 29 | } 30 | 31 | /** 32 | * Method to get property Options 33 | * @param string $name 34 | * @param mixed $default 35 | * @return mixed 36 | */ 37 | public function getOption(string $name, $default = null) 38 | { 39 | $value = array_key_exists($name, $this->options) ? $this->options[$name] : $default; 40 | 41 | if ($value && ($value instanceof \Closure)) { 42 | $value = $value(); 43 | } 44 | 45 | return $value; 46 | } 47 | 48 | /** 49 | * Method to set property options 50 | * @param string $name 51 | * @param mixed $value 52 | * @return static Return self to support chaining. 53 | */ 54 | public function setOption($name, $value) 55 | { 56 | $this->options[$name] = $value; 57 | 58 | return $this; 59 | } 60 | 61 | /** 62 | * delete a option 63 | * @param $name 64 | * @return mixed|null 65 | */ 66 | public function delOption($name) 67 | { 68 | $value = null; 69 | 70 | if ($this->hasOption($name)) { 71 | $value = $this->getOption($name); 72 | 73 | unset($this->options[$name]); 74 | } 75 | 76 | return $value; 77 | } 78 | 79 | /** 80 | * Method to get property Options 81 | * @return array 82 | */ 83 | public function getOptions(): array 84 | { 85 | return $this->options; 86 | } 87 | 88 | /** 89 | * Method to set property options 90 | * @param array $options 91 | * @param bool $merge 92 | * @return static Return self to support chaining. 93 | */ 94 | public function setOptions(array $options, $merge = true) 95 | { 96 | $this->options = $merge ? Arr::merge($this->options, $options) : $options; 97 | 98 | return $this; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/Event/EventTrait.php: -------------------------------------------------------------------------------- 1 | bool, // is once event 31 | * ] 32 | */ 33 | private $events = []; 34 | 35 | /** 36 | * @var array 37 | */ 38 | private $eventHandlers = []; 39 | 40 | /** 41 | * register a event handler 42 | * @param $event 43 | * @param callable $handler 44 | * @param bool $once 45 | */ 46 | public function on($event, callable $handler, $once = false): void 47 | { 48 | if ($this->isSupportedEvent($event)) { 49 | $this->eventHandlers[$event][] = $handler; 50 | $this->events[$event] = (bool)$once; 51 | } 52 | } 53 | 54 | /** 55 | * register a once event handler 56 | * @param $event 57 | * @param callable $handler 58 | */ 59 | public function once($event, callable $handler): void 60 | { 61 | $this->on($event, $handler, true); 62 | } 63 | 64 | /** 65 | * trigger event 66 | * @param $event 67 | * @param array $args 68 | * @return bool 69 | */ 70 | public function fire($event, array $args = []): bool 71 | { 72 | if (!isset($this->events[$event])) { 73 | return false; 74 | } 75 | 76 | // call event handlers of the event. 77 | foreach ((array)$this->eventHandlers[$event] as $cb) { 78 | // return FALSE to stop go on handle. 79 | if (false === PhpHelper::call($cb, ...$args)) { 80 | break; 81 | } 82 | } 83 | 84 | // is a once event, remove it 85 | if ($this->events[$event]) { 86 | return $this->off($event); 87 | } 88 | 89 | return true; 90 | } 91 | 92 | /** 93 | * remove event and it's handlers 94 | * @param string $event 95 | * @return mixed 96 | */ 97 | public function off($event) 98 | { 99 | if ($this->hasEvent($event)) { 100 | $handler = $this->eventHandlers[$event]; 101 | 102 | unset($this->events[$event], $this->eventHandlers[$event]); 103 | 104 | return $handler; 105 | } 106 | 107 | return null; 108 | } 109 | 110 | /** 111 | * clearEvents 112 | */ 113 | public function clearEvents(): void 114 | { 115 | $this->events = $this->eventHandlers = []; 116 | } 117 | 118 | /** 119 | * @param $event 120 | * @return bool 121 | */ 122 | public function hasEvent($event): bool 123 | { 124 | return isset($this->events[$event]); 125 | } 126 | 127 | /** 128 | * @param $event 129 | * @return bool 130 | */ 131 | public function isOnce($event): bool 132 | { 133 | if ($this->hasEvent($event)) { 134 | return $this->events[$event]; 135 | } 136 | 137 | return false; 138 | } 139 | 140 | /** 141 | * check $name is a supported event name 142 | * @param $event 143 | * @return bool 144 | */ 145 | public function isSupportedEvent($event): bool 146 | { 147 | if (!$event || !preg_match('/[a-zA-z][\w-]+/', $event)) { 148 | return false; 149 | } 150 | 151 | if ($ets = $this->supportedEvents) { 152 | return \in_array($event, $ets, true); 153 | } 154 | 155 | return true; 156 | } 157 | 158 | /** 159 | * @return array 160 | */ 161 | public function getSupportEvents(): array 162 | { 163 | return $this->supportedEvents; 164 | } 165 | 166 | /** 167 | * @param array $supportedEvents 168 | */ 169 | public function setSupportEvents(array $supportedEvents): void 170 | { 171 | $this->supportedEvents = $supportedEvents; 172 | } 173 | 174 | /** 175 | * @return array 176 | */ 177 | public function getEvents(): array 178 | { 179 | return $this->events; 180 | } 181 | 182 | /** 183 | * @return int 184 | */ 185 | public function getEventCount(): int 186 | { 187 | return \count($this->events); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/Event/FixedEventStaticTrait.php: -------------------------------------------------------------------------------- 1 | bool, // is once event 31 | * ] 32 | */ 33 | private static $events = []; 34 | 35 | /** 36 | * events and handlers 37 | * @var array 38 | * [ 39 | * 'event' => callable, // event handler 40 | * ] 41 | */ 42 | private static $eventHandlers = []; 43 | 44 | /** 45 | * register a event handler 46 | * @param $event 47 | * @param callable $handler 48 | * @param bool $once 49 | */ 50 | public static function on($event, callable $handler, $once = false): void 51 | { 52 | if (self::isSupportedEvent($event)) { 53 | self::$eventHandlers[$event][] = $handler; 54 | self::$events[$event] = (bool)$once; 55 | } 56 | } 57 | 58 | /** 59 | * register a once event handler 60 | * @param $event 61 | * @param callable $handler 62 | */ 63 | public static function once($event, callable $handler): void 64 | { 65 | self::on($event, $handler, true); 66 | } 67 | 68 | /** 69 | * trigger event 70 | * @param $event 71 | * @param array $args 72 | * @return bool 73 | */ 74 | public static function fire($event, array $args = []): bool 75 | { 76 | if (!isset(self::$events[$event])) { 77 | return false; 78 | } 79 | 80 | // call event handlers of the event. 81 | foreach ((array)self::$eventHandlers[$event] as $cb) { 82 | // return FALSE to stop go on handle. 83 | if (false === PhpHelper::call($cb, ...$args)) { 84 | break; 85 | } 86 | } 87 | 88 | // is a once event, remove it 89 | if (self::$events[$event]) { 90 | return self::off($event); 91 | } 92 | 93 | return true; 94 | } 95 | 96 | /** 97 | * remove event and it's handlers 98 | * @param $event 99 | * @return bool 100 | */ 101 | public static function off($event): bool 102 | { 103 | if (self::hasEvent($event)) { 104 | unset(self::$events[$event], self::$eventHandlers[$event]); 105 | 106 | return true; 107 | } 108 | 109 | return false; 110 | } 111 | 112 | /** 113 | * @param $event 114 | * @return bool 115 | */ 116 | public static function hasEvent($event): bool 117 | { 118 | return isset(self::$events[$event]); 119 | } 120 | 121 | /** 122 | * @param $event 123 | * @return bool 124 | */ 125 | public static function isOnce($event): bool 126 | { 127 | if (self::hasEvent($event)) { 128 | return self::$events[$event]; 129 | } 130 | 131 | return false; 132 | } 133 | 134 | /** 135 | * check $name is a supported event name 136 | * @param $event 137 | * @return bool 138 | */ 139 | public static function isSupportedEvent($event): bool 140 | { 141 | if (!$event || !preg_match('/[a-zA-z][\w-]+/', $event)) { 142 | return false; 143 | } 144 | 145 | if ($ets = self::$supportedEvents) { 146 | return \in_array($event, $ets, true); 147 | } 148 | 149 | return true; 150 | } 151 | 152 | /** 153 | * @return array 154 | */ 155 | public static function getSupportEvents(): array 156 | { 157 | return self::$supportedEvents; 158 | } 159 | 160 | /** 161 | * @param array $supportedEvents 162 | */ 163 | public static function setSupportEvents(array $supportedEvents): void 164 | { 165 | self::$supportedEvents = $supportedEvents; 166 | } 167 | 168 | /** 169 | * @return array 170 | */ 171 | public static function getEvents(): array 172 | { 173 | return self::$events; 174 | } 175 | 176 | /** 177 | * @return int 178 | */ 179 | public static function countEvents(): int 180 | { 181 | return \count(self::$events); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/Event/FixedEventTrait.php: -------------------------------------------------------------------------------- 1 | getSupportedEvents(), true); 40 | } 41 | 42 | /** 43 | * @param $event 44 | * @return bool 45 | */ 46 | public function hasEventHandler($event): bool 47 | { 48 | if (false === ($key = array_search($event, $this->getSupportedEvents(), true))) { 49 | return false; 50 | } 51 | 52 | return isset($this->eventHandlers[$key]); 53 | } 54 | 55 | /** 56 | * @return \SplFixedArray 57 | */ 58 | public function getEventHandlers(): \SplFixedArray 59 | { 60 | return $this->eventHandlers; 61 | } 62 | 63 | /** 64 | * @return int 65 | */ 66 | public function getEventCount(): int 67 | { 68 | return $this->eventHandlers->count(); 69 | } 70 | 71 | /** 72 | * @param string $event 73 | * @return callable 74 | */ 75 | public function getEventHandler(string $event): callable 76 | { 77 | if (false === ($key = array_search($event, $this->getSupportedEvents(), true))) { 78 | return null; 79 | } 80 | 81 | if (!isset($this->eventHandlers[$key])) { 82 | return null; 83 | } 84 | 85 | return $this->eventHandlers[$key]; 86 | } 87 | 88 | ///////////////////////////////////////////////////////////////////////////////////////// 89 | /// events method 90 | ///////////////////////////////////////////////////////////////////////////////////////// 91 | 92 | /** 93 | * register a event callback 94 | * @param string $event event name 95 | * @param callable $cb event callback 96 | * @param bool $replace replace exists's event cb 97 | * @throws \InvalidArgumentException 98 | */ 99 | public function on(string $event, callable $cb, bool $replace = false): void 100 | { 101 | if (false === ($key = array_search($event, $this->getSupportedEvents(), true))) { 102 | $sup = implode(',', $this->getSupportedEvents()); 103 | 104 | throw new \InvalidArgumentException("The want registered event [$event] is not supported. Supported: $sup"); 105 | } 106 | 107 | // init property 108 | if ($this->eventHandlers === null) { 109 | $this->eventHandlers = new \SplFixedArray(\count($this->getSupportedEvents())); 110 | } 111 | 112 | if (!$replace && isset($this->eventHandlers[$key])) { 113 | throw new \InvalidArgumentException("The want registered event [$event] have been registered! don't allow replace."); 114 | } 115 | 116 | $this->eventHandlers[$key] = $cb; 117 | } 118 | 119 | /** 120 | * remove event handler 121 | * @param string $event 122 | * @return bool 123 | */ 124 | public function off(string $event): bool 125 | { 126 | if (false === ($key = array_search($event, $this->getSupportedEvents(), true))) { 127 | return null; 128 | } 129 | 130 | if (!isset($this->eventHandlers[$key]) || !($cb = $this->eventHandlers[$key])) { 131 | return null; 132 | } 133 | 134 | $this->eventHandlers[$key] = null; 135 | 136 | return $cb; 137 | } 138 | 139 | /** 140 | * @param string $event 141 | * @param array $args 142 | * @return mixed 143 | * @throws \InvalidArgumentException 144 | */ 145 | protected function fire(string $event, array $args = []) 146 | { 147 | if (false === ($key = array_search($event, $this->getSupportedEvents(), true))) { 148 | throw new \InvalidArgumentException("Trigger a not exists's event: $event."); 149 | } 150 | 151 | if (!isset($this->eventHandlers[$key]) || !($cb = $this->eventHandlers[$key])) { 152 | return null; 153 | } 154 | 155 | return PhpHelper::call($cb, ...$args); 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/Event/LiteEventStaticTrait.php: -------------------------------------------------------------------------------- 1 | _events[$name])) { 37 | $this->_events[$name] = $cb; 38 | } 39 | } 40 | 41 | /** 42 | * @param string $name 43 | * @param array $args 44 | * @return mixed 45 | */ 46 | protected function fire($name, array $args = []) 47 | { 48 | if (!isset($this->_events[$name]) || !($cb = $this->_events[$name])) { 49 | return null; 50 | } 51 | 52 | return Php::call($cb, ...$args); 53 | } 54 | 55 | /** 56 | * @param $name 57 | * @return mixed 58 | */ 59 | public function off($name) 60 | { 61 | $cb = null; 62 | 63 | if (isset($this->_events[$name])) { 64 | $cb = $this->_events[$name]; 65 | unset($this->_events[$name]); 66 | } 67 | 68 | return $cb; 69 | } 70 | 71 | /** 72 | * @param string $name 73 | * @return mixed 74 | */ 75 | public function getEventHandler($name) 76 | { 77 | return $this->_events[$name] ?? null; 78 | } 79 | 80 | /** 81 | * @return array 82 | */ 83 | public function getEvents(): array 84 | { 85 | return $this->_events; 86 | } 87 | 88 | /** 89 | * @return int 90 | */ 91 | public function getEventCount(): int 92 | { 93 | return \count($this->_events); 94 | } 95 | 96 | /** 97 | * clearEvents 98 | */ 99 | public function clearEvents(): void 100 | { 101 | $this->_events = []; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/LiteContainerStaticTrait.php: -------------------------------------------------------------------------------- 1 | logger = function(){ 161 | * return new xx\yy\Logger; 162 | * }; 163 | * ``` 164 | * @param string $name 165 | * @param mixed $service 166 | * @return bool 167 | */ 168 | public function __set($name, $service) 169 | { 170 | return static::set($name, $service); 171 | } 172 | 173 | /** 174 | * allow call service by property 175 | * ``` 176 | * $logger = $app->logger; 177 | * ``` 178 | * @param string $name service name 179 | * @return mixed 180 | */ 181 | public function __get($name) 182 | { 183 | return static::get($name); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/LiteContainerTrait.php: -------------------------------------------------------------------------------- 1 | set($name, $service, $replace); 43 | 44 | return $this; 45 | } 46 | 47 | /** 48 | * register a app service 49 | * @param string $name 50 | * @param mixed $service service 51 | * @param bool $replace replace exists service 52 | * @return bool 53 | * @throws \LogicException 54 | */ 55 | public function set($name, $service, $replace = false): bool 56 | { 57 | // have been used. 58 | if (isset(self::$instances[$name])) { 59 | throw new \LogicException("The service [$name] have been instanced, don't allow override it."); 60 | } 61 | 62 | // setting 63 | if ($replace || !isset(self::$services[$name])) { 64 | self::$services[$name] = $service; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | /** 71 | * get a app service by name 72 | * if is a closure, only run once. 73 | * @param string $name 74 | * @param bool $call if service is 'Closure', call it. 75 | * @return mixed 76 | * @throws \RuntimeException 77 | */ 78 | public function get($name, $call = true) 79 | { 80 | if (!isset(self::$services[$name])) { 81 | throw new \RuntimeException("The service [$name] don't register."); 82 | } 83 | 84 | $service = self::$services[$name]; 85 | 86 | if (\is_object($service) && $service instanceof \Closure && $call) { 87 | if (!isset(self::$instances[$name])) { 88 | self::$instances[$name] = $service($this); 89 | } 90 | 91 | return self::$instances[$name]; 92 | } 93 | 94 | return $service; 95 | } 96 | 97 | /** 98 | * @param string $name 99 | * @return mixed 100 | * @throws \RuntimeException 101 | */ 102 | public function raw($name) 103 | { 104 | if (!isset(self::$services[$name])) { 105 | throw new \RuntimeException("The service [$name] don't register."); 106 | } 107 | 108 | return self::$services[$name]; 109 | } 110 | 111 | /** 112 | * create a app service by name 113 | * it always return a new instance. 114 | * @param string $name 115 | * @return mixed 116 | * @throws \RuntimeException 117 | */ 118 | public function factory($name) 119 | { 120 | if (!isset(self::$services[$name])) { 121 | throw new \RuntimeException("The service [$name] don't register."); 122 | } 123 | 124 | $service = self::$services[$name]; 125 | 126 | if (\is_object($service) && method_exists($service, '__invoke')) { 127 | return $service($this); 128 | } 129 | 130 | return $service; 131 | } 132 | 133 | /** 134 | * @param $name 135 | * @return bool 136 | */ 137 | public function has($name): bool 138 | { 139 | return isset(self::$services[$name]); 140 | } 141 | 142 | /** 143 | * @return array 144 | */ 145 | public function getServiceNames(): array 146 | { 147 | return array_keys(self::$services); 148 | } 149 | 150 | /** 151 | * @param $name 152 | * @return bool 153 | */ 154 | public function __isset($name) 155 | { 156 | return $this->has($name); 157 | } 158 | 159 | /** 160 | * allow register a app service by property 161 | * ``` 162 | * $app->logger = function(){ 163 | * return new xx\yy\Logger; 164 | * }; 165 | * ``` 166 | * @param string $name 167 | * @param mixed $service 168 | * @return bool 169 | */ 170 | public function __set($name, $service) 171 | { 172 | return $this->set($name, $service); 173 | } 174 | 175 | /** 176 | * allow call service by property 177 | * ``` 178 | * $logger = $app->logger; 179 | * ``` 180 | * @param string $name service name 181 | * @return mixed 182 | */ 183 | public function __get($name) 184 | { 185 | return $this->get($name); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/LogProfileTrait.php: -------------------------------------------------------------------------------- 1 | [ 40 | 'startTime' => microtime(true), 41 | 'startMem' => memory_get_usage(), 42 | ], 43 | '_profile_start' => $context, 44 | '_profile_end' => null, 45 | ]; 46 | 47 | $this->activeKey = $category . '|' . $name; 48 | $this->profiles[$category][$name] = $data; 49 | } 50 | 51 | /** 52 | * mark data analysis end 53 | * @param string|null $title 54 | * @param array $context 55 | */ 56 | public function profileEnd($title = null, array $context = []): void 57 | { 58 | if (!$this->activeKey) { 59 | return; 60 | } 61 | 62 | [$category, $name] = explode('|', $this->activeKey); 63 | 64 | if (isset($this->profiles[$category][$name])) { 65 | $data = $this->profiles[$category][$name]; 66 | 67 | $old = $data['_profile_stats']; 68 | $data['_profile_stats'] = PhpHelper::runtime($old['startTime'], $old['startMem']); 69 | $data['_profile_end'] = $context; 70 | 71 | $title = $category . ' - ' . ($title ?: $name); 72 | 73 | $this->activeKey = null; 74 | $this->log(Logger::DEBUG, $title, $data); 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/LogShortTrait.php: -------------------------------------------------------------------------------- 1 | resolveAlias($name); 31 | } 32 | 33 | foreach ((array)$alias as $aliasName) { 34 | if (!isset($this->aliases[$aliasName])) { 35 | $this->aliases[$aliasName] = $name; 36 | } 37 | } 38 | 39 | return true; 40 | } 41 | 42 | /** 43 | * @param string $alias 44 | * @return mixed 45 | */ 46 | public function resolveAlias(string $alias) 47 | { 48 | return $this->aliases[$alias] ?? $alias; 49 | } 50 | 51 | /** 52 | * @param $alias 53 | * @return bool 54 | */ 55 | public function hasAlias($alias): bool 56 | { 57 | return isset($this->aliases[$alias]); 58 | } 59 | 60 | /** 61 | * @return array 62 | */ 63 | public function getAliases(): array 64 | { 65 | return $this->aliases; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/PathAliasTrait.php: -------------------------------------------------------------------------------- 1 | $realPath) { 77 | // 1th char must is '@' 78 | if (!$alias || $alias[0] !== '@') { 79 | continue; 80 | } 81 | 82 | self::$aliases[$alias] = self::alias($realPath); 83 | } 84 | } 85 | 86 | /** 87 | * @return array 88 | */ 89 | public static function getAliases(): array 90 | { 91 | return self::$aliases; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/PathResolverTrait.php: -------------------------------------------------------------------------------- 1 | pathResolver) { 31 | return $path; 32 | } 33 | 34 | return Php::call($this->pathResolver, $path); 35 | } 36 | 37 | /** 38 | * @return callable 39 | */ 40 | public function getPathResolver(): callable 41 | { 42 | return $this->pathResolver; 43 | } 44 | 45 | /** 46 | * @param callable $pathResolver 47 | */ 48 | public function setPathResolver(callable $pathResolver): void 49 | { 50 | $this->pathResolver = $pathResolver; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/helper-utils/src/Traits/RuntimeProfileTrait.php: -------------------------------------------------------------------------------- 1 | [ 45 | 'startTime' => microtime(true), 46 | 'startMem' => memory_get_usage(), 47 | ], 48 | '_profile_start' => $context, 49 | '_profile_end' => null, 50 | '_profile_msg' => null, 51 | ]; 52 | 53 | $profileKey = $category . '|' . $name; 54 | 55 | if (\in_array($profileKey, self::$keyQueue, 1)) { 56 | throw new \InvalidArgumentException("Your added profile name [$name] have been exists!"); 57 | } 58 | 59 | self::$keyQueue[] = $profileKey; 60 | self::$profiles[$category][$name] = $data; 61 | } 62 | 63 | /** 64 | * mark data analysis end 65 | * @param string|null $msg 66 | * @param array $context 67 | * @return bool|array 68 | */ 69 | public static function profileEnd($msg = null, array $context = []) 70 | { 71 | if (!$latestKey = array_pop(self::$keyQueue)) { 72 | return false; 73 | } 74 | 75 | [$category, $name] = explode('|', $latestKey); 76 | 77 | if (isset(self::$profiles[$category][$name])) { 78 | $data = self::$profiles[$category][$name]; 79 | 80 | $old = $data['_profile_stats']; 81 | $data['_profile_stats'] = PhpHelper::runtime($old['startTime'], $old['startMem']); 82 | $data['_profile_end'] = $context; 83 | $data['_profile_msg'] = $msg; 84 | 85 | // $title = $category . ' - ' . ($title ?: $name); 86 | 87 | self::$profiles[$category][$name] = $data; 88 | // self::$log(Logger::DEBUG, $title, $data); 89 | 90 | return $data; 91 | } 92 | 93 | return false; 94 | } 95 | 96 | /** 97 | * @param null|string $name 98 | * @param string $category 99 | * @return array 100 | */ 101 | public static function getProfileData($name = null, $category = 'application'): array 102 | { 103 | if ($name) { 104 | return self::$profiles[$category][$name] ?? []; 105 | } 106 | 107 | if ($category) { 108 | return self::$profiles[$category] ?? []; 109 | } 110 | 111 | return self::$profiles; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/helper-utils/src/Util/AopProxy.php: -------------------------------------------------------------------------------- 1 | addProxy('FileLogger::log', function() { 18 | * echo 'before add log'; 19 | * }, 'before'); 20 | * $aop->addProxy('FileLogger::log', function() { 21 | * echo 'after add log'; 22 | * }, 'after'); 23 | * $logger = new FileLogger; 24 | * // not use: 25 | * // $logger->log('message'); 26 | * // should: 27 | * $aop->proxy($logger, 'log', ['message']); 28 | * // equal 29 | * $aop->proxy($logger)->call('log', ['message']); 30 | * // equal 31 | * $aop->proxy($logger)->log('message'); // by __call 32 | * // equal 33 | * $aop($logger)->log('message'); // by __invoke 34 | * // equal 35 | * $aop($logger, 'log', ['message']); // by __invoke 36 | */ 37 | class AopProxy 38 | { 39 | use AopProxyAwareTrait; 40 | 41 | /** 42 | * @var array 43 | */ 44 | protected $proxyMap = []; 45 | 46 | /** 47 | * AopProxy constructor. 48 | * @param array $proxyMap 49 | */ 50 | public function __construct(array $proxyMap = []) 51 | { 52 | $this->setProxyMap($proxyMap); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/helper-utils/src/Util/DataProxy.php: -------------------------------------------------------------------------------- 1 | 'handler', 22 | * 'getArticleList' => [ArticleDao::class, 'getArticleList'], 23 | * ] 24 | */ 25 | protected $proxies = []; 26 | 27 | public function __construct(array $proxies = []) 28 | { 29 | $this->proxies = $proxies; 30 | } 31 | 32 | /** 33 | * @param string $method 34 | * @param array $args 35 | * @return mixed 36 | */ 37 | public function __call($method, array $args) 38 | { 39 | return $this->call($method, $args); 40 | } 41 | 42 | /** 43 | * @param string $name 44 | * @param array $args 45 | * @return mixed 46 | * @throws \RuntimeException 47 | */ 48 | public function call(string $name, array $args) 49 | { 50 | if ($this->hasName($name)) { 51 | $handler = $this->proxies[$name]; 52 | return $handler(...$args); 53 | } 54 | 55 | throw new \RuntimeException("Called method $name is not exists."); 56 | } 57 | 58 | /** 59 | * @param string $name 60 | * @param callable $callback 61 | */ 62 | public function add(string $name, callable $callback): void 63 | { 64 | if (!isset($this->proxies[$name])) { 65 | $this->proxies[$name] = $callback; 66 | } 67 | } 68 | 69 | /** 70 | * @param string $name 71 | * @param callable $callback 72 | */ 73 | public function addProxy(string $name, callable $callback): void 74 | { 75 | if (!isset($this->proxies[$name])) { 76 | $this->proxies[$name] = $callback; 77 | } 78 | } 79 | 80 | /** 81 | * @param string $name 82 | * @param callable $callback 83 | */ 84 | public function setProxy(string $name, callable $callback): void 85 | { 86 | if (!isset($this->proxies[$name])) { 87 | $this->proxies[$name] = $callback; 88 | } 89 | } 90 | 91 | /** 92 | * @param string $name 93 | * @return bool 94 | */ 95 | public function hasName(string $name): bool 96 | { 97 | return isset($this->proxies[$name]); 98 | } 99 | 100 | /** 101 | * @param array $proxies 102 | */ 103 | public function addProxies(array $proxies): void 104 | { 105 | foreach ($proxies as $name => $callback) { 106 | $this->addProxy($name, $callback); 107 | } 108 | } 109 | 110 | /** 111 | * @return array 112 | */ 113 | public function getProxies(): array 114 | { 115 | return $this->proxies; 116 | } 117 | 118 | /** 119 | * @param array $proxies 120 | */ 121 | public function setProxies(array $proxies): void 122 | { 123 | $this->proxies = $proxies; 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /src/helper-utils/src/Util/DataResult.php: -------------------------------------------------------------------------------- 1 | value = $value; 29 | } 30 | 31 | public function get() 32 | { 33 | return $this->value; 34 | } 35 | 36 | /** 37 | * @return mixed 38 | */ 39 | public function getValue() 40 | { 41 | return $this->value; 42 | } 43 | 44 | /** 45 | * @param mixed $value 46 | */ 47 | public function setValue($value): void 48 | { 49 | $this->value = $value; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/helper-utils/src/Util/DeferredCallable.php: -------------------------------------------------------------------------------- 1 | callable = $callable; 29 | } 30 | 31 | /** 32 | * @param array $args 33 | * @return mixed 34 | * @throws \InvalidArgumentException 35 | */ 36 | public function __invoke(...$args) 37 | { 38 | $callable = $this->callable; 39 | 40 | if (\is_callable($callable)) { 41 | return PhpHelper::call($callable, ...$args); 42 | } 43 | 44 | if (\is_string($callable) && class_exists($callable)) { 45 | $obj = new $callable; 46 | 47 | if (method_exists($obj, '__invoke')) { 48 | return $obj(...$args); 49 | } 50 | 51 | throw new \InvalidArgumentException('the defined callable is cannot be called!'); 52 | } 53 | 54 | throw new \InvalidArgumentException('the defined callable is error!'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/helper-utils/src/Util/Pipeline.php: -------------------------------------------------------------------------------- 1 | stages = new \SplObjectStorage; 24 | } 25 | 26 | /** 27 | * {@inheritdoc} 28 | */ 29 | public function add(callable $stage) 30 | { 31 | if ($stage instanceof $this) { 32 | $stage->add(function ($payload) { 33 | return $this->invokeStage($payload); 34 | }); 35 | } 36 | 37 | $this->stages->attach($stage); 38 | 39 | return $this; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function run($payload) 46 | { 47 | $this->stages->rewind(); 48 | 49 | return $this->invokeStage($payload); 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function __invoke($payload) 56 | { 57 | return $this->run($payload); 58 | } 59 | 60 | private function invokeStage($payload) 61 | { 62 | $stage = $this->stages->current(); 63 | $this->stages->next(); 64 | 65 | if (\is_callable($stage)) { 66 | return $stage($payload, function ($payload) { 67 | return $this->invokeStage($payload); 68 | }); 69 | } 70 | 71 | return $payload; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/helper-utils/src/Util/PipelineInterface.php: -------------------------------------------------------------------------------- 1 | $baseDir . '/libs/di/test', 22 | ]; 23 | 24 | spl_autoload_register(function ($class) use ($map) { 25 | foreach ($map as $np => $dir) { 26 | if (0 === strpos($class, $np)) { 27 | $path = str_replace('\\', '/', substr($class, strlen($np))); 28 | $file = $dir . "/{$path}.php"; 29 | 30 | if (is_file($file)) { 31 | __include_file($file); 32 | } 33 | } 34 | } 35 | }); 36 | 37 | function __include_file($file) 38 | { 39 | include $file; 40 | } 41 | -------------------------------------------------------------------------------- /toolkit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 'php toolkit', 22 | 'debug' => true, 23 | 'version' => '1.0.0', 24 | 'rootPath' => __DIR__, 25 | ]); 26 | $app->setLogo(" 27 | ____ __ ______ ____ _ __ 28 | / __ \/ /_ ____ /_ __/___ ____ / / /__(_) /_ 29 | / /_/ / __ \/ __ \ / / / __ \/ __ \/ / //_/ / __/ 30 | / ____/ / / / /_/ / / / / /_/ / /_/ / / ,< / / /_ 31 | /_/ /_/ /_/ .___/ /_/ \____/\____/_/_/|_/_/\__/ 32 | /_/ 33 | ", 'success'); 34 | 35 | // add commands 36 | $app->addController(DevController::class); 37 | 38 | // run 39 | $app->run(); 40 | --------------------------------------------------------------------------------