.gitattributes000064400000000054151360554270007446 0ustar00/tests export-ignore /.github export-ignore LICENSE000064400000002110151360554270005553 0ustar00The MIT License (MIT) Copyright (c) Taylor Otwell Copyright (c) Hyperf Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. composer.json000064400000004001151360554270007271 0ustar00{ "name": "hyperf/utils", "description": "A tools package that could help developer solved the problem quickly.", "license": "MIT", "keywords": [ "php", "swoole", "hyperf", "utils" ], "homepage": "https://hyperf.io", "support": { "docs": "https://hyperf.wiki", "issues": "https://github.com/hyperf/hyperf/issues", "pull-request": "https://github.com/hyperf/hyperf/pulls", "source": "https://github.com/hyperf/hyperf" }, "require": { "php": ">=7.2", "doctrine/inflector": "^2.0", "hyperf/code-parser": "~3.0.0", "hyperf/codec": "~3.0.0", "hyperf/collection": "~3.0.0", "hyperf/context": "~3.0.0", "hyperf/contract": "~3.0.0", "hyperf/coordinator": "~3.0.0", "hyperf/coroutine": "~3.0.0", "hyperf/engine": "^1.2|^2.0", "hyperf/macroable": "~3.0.0", "hyperf/serializer": "~3.0.0", "hyperf/stringable": "~3.0.0", "hyperf/support": "~3.0.0" }, "suggest": { "ext-swoole": "Required to use methods related to swoole (>=4.5).", "symfony/var-dumper": "Required to use the dd function (^5.0|^6.0).", "symfony/serializer": "Required to use SymfonyNormalizer (^5.0|^6.0)", "symfony/property-access": "Required to use SymfonyNormalizer (^5.0|^6.0)", "hyperf/di": "Required to use ExceptionNormalizer", "nikic/php-parser": "Required to use PhpParser. (^4.0)", "ramsey/uuid": "Required to use uuid and orderedUuid methods", "symfony/uid": "Required to use ulid method" }, "autoload": { "files": [ "src/Functions.php" ], "psr-4": { "Hyperf\\Utils\\": "src/" } }, "autoload-dev": { "psr-4": { "HyperfTest\\Utils\\": "tests/" } }, "config": { "sort-packages": true }, "extra": { "branch-alias": { "dev-master": "3.0-dev" } } } src/ApplicationContext.php000064400000000647151360554270011673 0ustar00 self::$interval || self::$lastCleared || (self::$lastCleared + self::$interval < $now) ) { self::forceClear($filename); self::$lastCleared = $now; } } public static function forceClear(?string $filename = null): void { if ($filename !== null) { clearstatcache(true, $filename); } else { clearstatcache(); } } public static function getInterval(): int { return self::$interval; } public static function setInterval(int $interval) { self::$interval = $interval; } } src/CodeGen/Package.php000064400000000616151360554270010716 0ustar00toArray(); } try { $json = json_encode($data, $flags | JSON_THROW_ON_ERROR, $depth); } catch (Throwable $exception) { throw new InvalidArgumentException($exception->getMessage(), (int) $exception->getCode(), $exception); } return $json; } /** * @throws InvalidArgumentException */ public static function decode(string $json, bool $assoc = true, int $depth = 512, int $flags = 0): mixed { try { $decode = json_decode($json, $assoc, $depth, $flags | JSON_THROW_ON_ERROR); } catch (Throwable $exception) { throw new InvalidArgumentException($exception->getMessage(), (int) $exception->getCode(), $exception); } return $decode; } } src/Codec/Xml.php000064400000003410151360554270007627 0ustar00toArray(); } else { $data = (array) $data; } if ($parentNode === null) { $xml = new SimpleXMLElement('' . "<{$root}>"); } else { $xml = $parentNode; } foreach ($data as $key => $value) { if (is_array($value)) { self::toXml($value, $xml->addChild($key)); } else { if (is_numeric($key)) { $xml->addChild('item' . $key, (string) $value); } else { $xml->addChild($key, (string) $value); } } } return trim($xml->asXML()); } public static function toArray($xml): array { $respObject = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOERROR); if ($respObject === false) { throw new InvalidArgumentException('Syntax error.'); } return json_decode(json_encode($respObject), true); } } src/Collection.php000064400000001031151360554270010142 0ustar00offsetGet('packages') ?? []; $packagesDev = self::$content->offsetGet('packages-dev') ?? []; foreach (array_merge($packages, $packagesDev) as $package) { $packageName = ''; foreach ($package ?? [] as $key => $value) { if ($key === 'name') { $packageName = $value; continue; } switch ($key) { case 'extra': $packageName && self::$extra[$packageName] = $value; break; case 'scripts': $packageName && self::$scripts[$packageName] = $value; break; case 'version': $packageName && self::$versions[$packageName] = $value; break; } } } } return self::$content; } public static function getJsonContent(): Collection { if (! self::$json) { $path = BASE_PATH . '/composer.json'; if (! is_readable($path)) { throw new RuntimeException('composer.json is not readable.'); } self::$json = collect(json_decode(file_get_contents($path), true)); } return self::$json; } public static function discoverLockFile(): string { $path = ''; if (is_readable(BASE_PATH . '/composer.lock')) { $path = BASE_PATH . '/composer.lock'; } return $path; } public static function getMergedExtra(string $key = null) { if (! self::$extra) { self::getLockContent(); } if ($key === null) { return self::$extra; } $extra = []; foreach (self::$extra as $project => $config) { foreach ($config ?? [] as $configKey => $item) { if ($key === $configKey && $item) { foreach ($item as $k => $v) { if (is_array($v)) { $extra[$k] = array_merge($extra[$k] ?? [], $v); } else { $extra[$k][] = $v; } } } } } return $extra; } public static function getLoader(): ClassLoader { if (! self::$classLoader) { self::$classLoader = self::findLoader(); } return self::$classLoader; } public static function setLoader(ClassLoader $classLoader): ClassLoader { self::$classLoader = $classLoader; return $classLoader; } public static function getScripts(): array { return self::$scripts; } public static function getVersions(): array { return self::$versions; } private static function findLoader(): ClassLoader { $loaders = spl_autoload_functions(); foreach ($loaders as $loader) { if (is_array($loader) && $loader[0] instanceof ClassLoader) { return $loader[0]; } } throw new RuntimeException('Composer loader not found.'); } } src/Contracts/Arrayable.php000064400000000566151360554270011725 0ustar00 1 && $value[0] === '"' && $value[$valueLength - 1] === '"') { return substr($value, 1, -1); } return $value; } } if (! function_exists('retry')) { /** * Retry an operation a given number of times. * * @param float|int $times * @param int $sleep millisecond * @throws \Throwable * @deprecated since 3.1, use \Hyperf\Support\retry instead. */ function retry($times, callable $callback, int $sleep = 0) { $attempts = 0; $backoff = new Backoff($sleep); beginning: try { return $callback(++$attempts); } catch (\Throwable $e) { if (--$times < 0) { throw $e; } $backoff->sleep(); goto beginning; } } } if (! function_exists('with')) { /** * Return the given value, optionally passed through the given callback. * * @param mixed $value * @deprecated since 3.1, use \Hyperf\Support\with instead. */ function with($value, callable $callback = null) { return is_null($callback) ? $value : $callback($value); } } if (! function_exists('collect')) { /** * Create a collection from the given value. * * @deprecated since 3.1, use \Hyperf\Collection\collect instead. * @param null|mixed $value * @return Collection */ function collect($value = null) { return new Collection($value); } } if (! function_exists('data_fill')) { /** * Fill in data where it's missing. * * @param mixed $target * @param array|string $key * @param mixed $value * * @deprecated since 3.1, use `Hyperf\Collection\data_fill()` instead. */ function data_fill(&$target, $key, $value) { return data_set($target, $key, $value, false); } } if (! function_exists('data_get')) { /** * Get an item from an array or object using "dot" notation. * * @param null|array|int|string $key * @param null|mixed $default * @param mixed $target * * @deprecated since 3.1, use `Hyperf\Collection\data_get()` instead. */ function data_get($target, $key, $default = null) { if (is_null($key)) { return $target; } $key = is_array($key) ? $key : explode('.', is_int($key) ? (string) $key : $key); while (! is_null($segment = array_shift($key))) { if ($segment === '*') { if ($target instanceof Collection) { $target = $target->all(); } elseif (! is_array($target)) { return value($default); } $result = []; foreach ($target as $item) { $result[] = data_get($item, $key); } return in_array('*', $key) ? Arr::collapse($result) : $result; } if (Arr::accessible($target) && Arr::exists($target, $segment)) { $target = $target[$segment]; } elseif (is_object($target) && isset($target->{$segment})) { $target = $target->{$segment}; } else { return value($default); } } return $target; } } if (! function_exists('data_set')) { /** * Set an item on an array or object using dot notation. * * @param mixed $target * @param array|string $key * @param bool $overwrite * @param mixed $value * * @deprecated since 3.1, use `Hyperf\Collection\data_set()` instead. */ function data_set(&$target, $key, $value, $overwrite = true) { $segments = is_array($key) ? $key : explode('.', $key); if (($segment = array_shift($segments)) === '*') { if (! Arr::accessible($target)) { $target = []; } if ($segments) { foreach ($target as &$inner) { data_set($inner, $segments, $value, $overwrite); } } elseif ($overwrite) { foreach ($target as &$inner) { $inner = $value; } } } elseif (Arr::accessible($target)) { if ($segments) { if (! Arr::exists($target, $segment)) { $target[$segment] = []; } data_set($target[$segment], $segments, $value, $overwrite); } elseif ($overwrite || ! Arr::exists($target, $segment)) { $target[$segment] = $value; } } elseif (is_object($target)) { if ($segments) { if (! isset($target->{$segment})) { $target->{$segment} = []; } data_set($target->{$segment}, $segments, $value, $overwrite); } elseif ($overwrite || ! isset($target->{$segment})) { $target->{$segment} = $value; } } else { $target = []; if ($segments) { $target[$segment] = []; data_set($target[$segment], $segments, $value, $overwrite); } elseif ($overwrite) { $target[$segment] = $value; } } return $target; } } if (! function_exists('head')) { /** * Get the first element of an array. Useful for method chaining. * * @param array $array * * @deprecated since 3.1, use `Hyperf\Collection\head()` instead. */ function head($array) { return reset($array); } } if (! function_exists('last')) { /** * Get the last element from an array. * * @param array $array * * @deprecated since 3.1, use `Hyperf\Collection\last()` instead. */ function last($array) { return end($array); } } if (! function_exists('tap')) { /** * Call the given Closure with the given value then return the value. * * @template TValue * * @param null|callable $callback * @param TValue $value * @return TValue * * @deprecated since 3.1, please use `Hyperf\Tappable\tap()` instead. */ function tap($value, $callback = null) { if (is_null($callback)) { return new HigherOrderTapProxy($value); } $callback($value); return $value; } } if (! function_exists('call')) { /** * Call a callback with the arguments. * * @param mixed $callback * @return null|mixed * @deprecated since 3.1, use \Hyperf\Support\call instead. */ function call($callback, array $args = []) { $result = null; if ($callback instanceof \Closure) { $result = $callback(...$args); } elseif (is_object($callback) || (is_string($callback) && function_exists($callback))) { $result = $callback(...$args); } elseif (is_array($callback)) { [$object, $method] = $callback; $result = is_object($object) ? $object->{$method}(...$args) : $object::$method(...$args); } else { $result = call_user_func_array($callback, $args); } return $result; } } if (! function_exists('go')) { /** * @return bool|int * * @deprecated since 3.1, use `Hyperf\Coroutine\go` instead. */ function go(callable $callable) { $id = Coroutine::create($callable); return $id > 0 ? $id : false; } } if (! function_exists('co')) { /** * @return bool|int * * @deprecated since 3.1, use `Hyperf\Coroutine\co` instead. */ function co(callable $callable) { $id = Coroutine::create($callable); return $id > 0 ? $id : false; } } if (! function_exists('defer')) { /** * @deprecated since 3.1, use `Hyperf\Coroutine\defer` instead. */ function defer(callable $callable): void { Coroutine::defer($callable); } } if (! function_exists('class_basename')) { /** * Get the class "basename" of the given object / class. * * @param object|string $class * @return string * @deprecated since 3.1, use \Hyperf\Support\class_basename instead. */ function class_basename($class) { $class = is_object($class) ? get_class($class) : $class; return basename(str_replace('\\', '/', $class)); } } if (! function_exists('trait_uses_recursive')) { /** * Returns all traits used by a trait and its traits. * * @param object|string $trait * @return array * @deprecated since 3.1, use \Hyperf\Support\trait_uses_recursive instead. */ function trait_uses_recursive($trait) { $traits = class_uses($trait); foreach ($traits as $trait) { $traits += trait_uses_recursive($trait); } return $traits; } } if (! function_exists('class_uses_recursive')) { /** * Returns all traits used by a class, its parent classes and trait of their traits. * * @param object|string $class * @return array * @deprecated since 3.1, use \Hyperf\Support\class_uses_recursive instead. */ function class_uses_recursive($class) { if (is_object($class)) { $class = get_class($class); } $results = []; /* @phpstan-ignore-next-line */ foreach (array_reverse(class_parents($class)) + [$class => $class] as $class) { $results += trait_uses_recursive($class); } return array_unique($results); } } if (! function_exists('setter')) { /** * Create a setter string. * @deprecated since 3.1, use \Hyperf\Support\setter instead. */ function setter(string $property): string { return 'set' . Str::studly($property); } } if (! function_exists('getter')) { /** * Create a getter string. * @deprecated since 3.1, use \Hyperf\Support\getter instead. */ function getter(string $property): string { return 'get' . Str::studly($property); } } if (! function_exists('parallel')) { /** * @param callable[] $callables * @param int $concurrent if $concurrent is equal to 0, that means unlimited * * @deprecated since 3.1, use `Hyperf\Coroutine\parallel` instead. */ function parallel(array $callables, int $concurrent = 0) { $parallel = new Parallel($concurrent); foreach ($callables as $key => $callable) { $parallel->add($callable, $key); } return $parallel->wait(); } } if (! function_exists('make')) { /** * Create an object instance, if the DI container exist in ApplicationContext, * then the object will be created by DI container via `make()` method, if not, * the object will create by `new` keyword. * @deprecated since 3.1, use \Hyperf\Support\make instead. */ function make(string $name, array $parameters = []) { if (ApplicationContext::hasContainer()) { $container = ApplicationContext::getContainer(); if (method_exists($container, 'make')) { return $container->make($name, $parameters); } } $parameters = array_values($parameters); return new $name(...$parameters); } } if (! function_exists('run')) { /** * Run callable in non-coroutine environment, all hook functions by Swoole only available in the callable. * * @param array|callable $callbacks * * @deprecated since 3.1, use `Hyperf\Coroutine\run` instead. */ function run($callbacks, int $flags = SWOOLE_HOOK_ALL): bool { if (Coroutine::inCoroutine()) { throw new RuntimeException('Function \'run\' only execute in non-coroutine environment.'); } \Swoole\Runtime::enableCoroutine($flags); /* @phpstan-ignore-next-line */ $result = \Swoole\Coroutine\run(...(array) $callbacks); \Swoole\Runtime::enableCoroutine(false); return $result; } } if (! function_exists('swoole_hook_flags')) { /** * Return the default swoole hook flags, you can rewrite it by defining `SWOOLE_HOOK_FLAGS`. * @deprecated since 3.1, use \Hyperf\Support\swoole_hook_flags instead. */ function swoole_hook_flags(): int { return defined('SWOOLE_HOOK_FLAGS') ? SWOOLE_HOOK_FLAGS : SWOOLE_HOOK_ALL; } } if (! function_exists('optional')) { /** * Provide access to optional objects. * * @param mixed $value * @return mixed * @deprecated since 3.1, use \Hyperf\Support\optional instead. */ function optional($value = null, callable $callback = null) { if (is_null($callback)) { return new Optional($value); } if (! is_null($value)) { return $callback($value); } return null; } } if (! function_exists('wait')) { /** * @deprecated since 3.1, use `Hyperf\Coroutine\wait` instead. */ function wait(Closure $closure, ?float $timeout = null) { if (ApplicationContext::hasContainer()) { $waiter = ApplicationContext::getContainer()->get(Waiter::class); return $waiter->wait($closure, $timeout); } return (new Waiter())->wait($closure, $timeout); } } // TODO: Removed when deleting `\Hyperf\Utils\Collection`. class_exists(\Hyperf\Utils\Collection::class); class_exists(\Hyperf\Utils\Filesystem\FileNotFoundException::class); class_exists(\Hyperf\Utils\Exception\IPReadFailedException::class); class_exists(\Hyperf\Utils\Exception\ParallelExecutionException::class); class_exists(\Hyperf\Utils\Exception\TimeoutException::class); class_exists(\Hyperf\Utils\Exception\WaitTimeoutException::class); class_exists(\Hyperf\Utils\Exception\InvalidArgumentException::class); class_exists(\Hyperf\Utils\Exception\ChannelClosedException::class); class_exists(\Hyperf\Utils\Exception\ExceptionThrower::class); src/HigherOrderCollectionProxy.php000064400000002623151360554270013337 0ustar00collection->{$this->method}(function ($value) use ($key) { return is_array($value) ? $value[$key] : $value->{$key}; }); } /** * Proxy a method call onto the collection items. */ public function __call(string $method, array $parameters) { return $this->collection->{$this->method}(function ($value) use ($method, $parameters) { return $value->{$method}(...$parameters); }); } } src/HigherOrderTapProxy.php000064400000001534151360554270011770 0ustar00target->{$method}(...$parameters); return $this->target; } } src/IPReader.php000064400000000576151360554270007517 0ustar00 $value) { foreach ($value['unicast'] as $item) { if (! isset($item['address'])) { continue; } if (! Str::contains($item['address'], ':') && $item['address'] !== '127.0.0.1') { $ips[$name] = $item['address']; } } } } if (is_array($ips) && ! empty($ips)) { return current($ips); } $name = gethostname(); if ($name === false) { throw new RuntimeException('Can not get the internal IP.'); } return gethostbyname($name); } } src/Optional.php000064400000000603151360554270007640 0ustar00passable = $passable; return $this; } /** * Set the array of pipes. * * @param array|mixed $pipes */ public function through($pipes): self { $this->pipes = is_array($pipes) ? $pipes : func_get_args(); return $this; } /** * Set the method to call on the pipes. */ public function via(string $method): self { $this->method = $method; return $this; } /** * Run the pipeline with a final destination callback. */ public function then(Closure $destination) { $pipeline = array_reduce(array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)); return $pipeline($this->passable); } /** * Run the pipeline and return the result. */ public function thenReturn() { return $this->then(fn ($passable) => $passable); } /** * Get the final piece of the Closure onion. */ protected function prepareDestination(Closure $destination): Closure { return static function ($passable) use ($destination) { return $destination($passable); }; } /** * Get a Closure that represents a slice of the application onion. */ protected function carry(): Closure { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { if (is_callable($pipe)) { // If the pipe is an instance of a Closure, we will just call it directly, but // otherwise we'll resolve the pipes out of the container and call it with // the appropriate method and arguments, returning the results back out. return $pipe($passable, $stack); } if (! is_object($pipe)) { [$name, $parameters] = $this->parsePipeString($pipe); // If the pipe is a string we will parse the string and resolve the class out // of the dependency injection container. We can then build a callable and // execute the pipe function giving in the parameters that are required. $pipe = $this->container->get($name); $parameters = array_merge([$passable, $stack], $parameters); } else { // If the pipe is already an object we'll just make a callable and pass it to // the pipe as-is. There is no need to do any extra parsing and formatting // since the object we're given was already a fully instantiated object. $parameters = [$passable, $stack]; } $carry = method_exists($pipe, $this->method) ? $pipe->{$this->method}(...$parameters) : $pipe(...$parameters); return $this->handleCarry($carry); }; }; } /** * Parse full pipe string to get name and parameters. * * @param string $pipe * @return array */ protected function parsePipeString($pipe) { [$name, $parameters] = array_pad(explode(':', $pipe, 2), 2, []); if (is_string($parameters)) { $parameters = explode(',', $parameters); } return [$name, $parameters]; } /** * Handle the value returned from each pipe before passing it to the next. * * @param mixed $carry * @return mixed */ protected function handleCarry($carry) { return $carry; } } src/Pluralizer.php000064400000007277151360554270010222 0ustar00pluralize($value); return static::matchCase($plural, $value); } /** * Get the singular form of an English word. * * @param string $value * @return string */ public static function singular($value) { $singular = static::getInflector()->singularize($value); return static::matchCase($singular, $value); } public static function setInflector(?Inflector $inflector): void { static::$inflector = $inflector; } /** * Get the inflector instance. */ public static function getInflector(): Inflector { if (is_null(static::$inflector)) { static::$inflector = new Inflector( new CachedWordInflector(new RulesetInflector( English\Rules::getSingularRuleset() )), new CachedWordInflector(new RulesetInflector( English\Rules::getPluralRuleset() )) ); } return static::$inflector; } /** * Determine if the given value is uncountable. * * @param string $value * @return bool */ protected static function uncountable($value) { return in_array(strtolower($value), static::$uncountable); } /** * Attempt to match the case on two strings. * * @param string $value * @param string $comparison * @return string */ protected static function matchCase($value, $comparison) { $functions = ['mb_strtolower', 'mb_strtoupper', 'ucfirst', 'ucwords']; foreach ($functions as $function) { if (call_user_func($function, $comparison) === $comparison) { return call_user_func($function, $value); } } return $value; } } src/Reflection/ClassInvoker.php000064400000000660151360554270012553 0ustar00serialize($obj, 'xml') * $serializer->decode($data, 'xml') * $serializer->denormalize($data, 'Class', 'xml') * * @deprecated since 3.1, use Hyperf\Serializer\Serializer instead. */ class Serializer extends \Hyperf\Serializer\Serializer { } src/Serializer/SerializerFactory.php000064400000000656151360554270013635 0ustar00