代码初始化

This commit is contained in:
2025-08-07 20:21:47 +08:00
commit 50f3a2dbb0
2191 changed files with 374790 additions and 0 deletions

View File

@@ -0,0 +1,142 @@
<?php
declare(strict_types=1);
namespace Yansongda\Supports\Traits;
trait Accessable
{
/**
* __get.
*
* @author yansongda <me@yansongda.cn>
*
* @return mixed
*/
public function __get(string $key)
{
return $this->get($key);
}
/**
* __set.
*
* @author yansongda <me@yansongda.cn>
*
* @param mixed $value
*
* @return mixed
*/
public function __set(string $key, $value)
{
return $this->set($key, $value);
}
/**
* get.
*
* @author yansongda <me@yansongda.cn>
*
* @param mixed $default
*
* @return mixed
*/
public function get(?string $key = null, $default = null)
{
if (is_null($key)) {
return method_exists($this, 'toArray') ? $this->toArray() : $default;
}
$method = 'get';
foreach (explode('_', $key) as $item) {
$method .= ucfirst($item);
}
if (method_exists($this, $method)) {
return $this->{$method}();
}
return $default;
}
/**
* set.
*
* @author yansongda <me@yansongda.cn>
*
* @param mixed $value
*
* @return $this
*/
public function set(string $key, $value)
{
$method = 'set';
foreach (explode('_', $key) as $item) {
$method .= ucfirst($item);
}
if (method_exists($this, $method)) {
return $this->{$method}($value);
}
return $this;
}
/**
* Whether a offset exists.
*
* @see https://php.net/manual/en/arrayaccess.offsetexists.php
*
* @param mixed $offset an offset to check for
*
* @return bool true on success or false on failure.
*
* The return value will be casted to boolean if non-boolean was returned.
*/
public function offsetExists($offset)
{
return !is_null($this->get($offset));
}
/**
* Offset to retrieve.
*
* @see https://php.net/manual/en/arrayaccess.offsetget.php
*
* @param mixed $offset the offset to retrieve
*
* @return mixed can return all value types
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
/**
* Offset to set.
*
* @see https://php.net/manual/en/arrayaccess.offsetset.php
*
* @param mixed $offset the offset to assign the value to
* @param mixed $value the value to set
*
* @return void
*/
public function offsetSet($offset, $value)
{
$this->set($offset, $value);
}
/**
* Offset to unset.
*
* @see https://php.net/manual/en/arrayaccess.offsetunset.php
*
* @param mixed $offset the offset to unset
*
* @return void
*/
public function offsetUnset($offset)
{
}
}

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Yansongda\Supports\Traits;
use ReflectionClass;
use Yansongda\Supports\Str;
trait Arrayable
{
/**
* toArray.
*
* @author yansongda <me@yansongda.cn>
*
* @throws \ReflectionException
*/
public function toArray(): array
{
$result = [];
foreach ((new ReflectionClass($this))->getProperties() as $item) {
$k = $item->getName();
$method = 'get'.Str::studly($k);
$result[Str::snake($k)] = method_exists($this, $method) ? $this->{$method}() : $this->{$k};
}
return $result;
}
}

View File

@@ -0,0 +1,229 @@
<?php
namespace Yansongda\Supports\Traits;
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;
/**
* Trait HasHttpRequest.
*
* @property string $baseUri
* @property float $timeout
* @property float $connectTimeout
*/
trait HasHttpRequest
{
/**
* Http client.
*
* @var Client|null
*/
protected $httpClient = null;
/**
* Http client options.
*
* @var array
*/
protected $httpOptions = [];
/**
* Send a GET request.
*
* @author yansongda <me@yansongda.cn>
*
* @return array|string
*/
public function get(string $endpoint, array $query = [], array $headers = [])
{
return $this->request('get', $endpoint, [
'headers' => $headers,
'query' => $query,
]);
}
/**
* Send a POST request.
*
* @author yansongda <me@yansongda.cn>
*
* @param string|array $data
*
* @return array|string
*/
public function post(string $endpoint, $data, array $options = [])
{
if (!is_array($data)) {
$options['body'] = $data;
} else {
$options['form_params'] = $data;
}
return $this->request('post', $endpoint, $options);
}
/**
* Send request.
*
* @author yansongda <me@yansongda.cn>
*
* @return array|string
*/
public function request(string $method, string $endpoint, array $options = [])
{
return $this->unwrapResponse($this->getHttpClient()->{$method}($endpoint, $options));
}
/**
* Set http client.
*
* @author yansongda <me@yansongda.cn>
*
* @return $this
*/
public function setHttpClient(Client $client): self
{
$this->httpClient = $client;
return $this;
}
/**
* Return http client.
*/
public function getHttpClient(): Client
{
if (is_null($this->httpClient)) {
$this->httpClient = $this->getDefaultHttpClient();
}
return $this->httpClient;
}
/**
* Get default http client.
*
* @author yansongda <me@yansongda.cn>
*/
public function getDefaultHttpClient(): Client
{
return new Client($this->getOptions());
}
/**
* setBaseUri.
*
* @author yansongda <me@yansongda.cn>
*
* @return $this
*/
public function setBaseUri(string $url): self
{
if (property_exists($this, 'baseUri')) {
$parsedUrl = parse_url($url);
$this->baseUri = ($parsedUrl['scheme'] ?? 'http').'://'.
$parsedUrl['host'].(isset($parsedUrl['port']) ? (':'.$parsedUrl['port']) : '');
}
return $this;
}
/**
* getBaseUri.
*
* @author yansongda <me@yansongda.cn>
*/
public function getBaseUri(): string
{
return property_exists($this, 'baseUri') ? $this->baseUri : '';
}
public function getTimeout(): float
{
return property_exists($this, 'timeout') ? $this->timeout : 5.0;
}
public function setTimeout(float $timeout): self
{
if (property_exists($this, 'timeout')) {
$this->timeout = $timeout;
}
return $this;
}
public function getConnectTimeout(): float
{
return property_exists($this, 'connectTimeout') ? $this->connectTimeout : 3.0;
}
public function setConnectTimeout(float $connectTimeout): self
{
if (property_exists($this, 'connectTimeout')) {
$this->connectTimeout = $connectTimeout;
}
return $this;
}
/**
* Get default options.
*
* @author yansongda <me@yansongda.cn>
*/
public function getOptions(): array
{
return array_merge([
'base_uri' => $this->getBaseUri(),
'timeout' => $this->getTimeout(),
'connect_timeout' => $this->getConnectTimeout(),
], $this->getHttpOptions());
}
/**
* setOptions.
*
* @author yansongda <me@yansongda.cn>
*
* @return $this
*/
public function setOptions(array $options): self
{
return $this->setHttpOptions($options);
}
public function getHttpOptions(): array
{
return $this->httpOptions;
}
public function setHttpOptions(array $httpOptions): self
{
$this->httpOptions = $httpOptions;
return $this;
}
/**
* Convert response.
*
* @author yansongda <me@yansongda.cn>
*
* @return array|string
*/
public function unwrapResponse(ResponseInterface $response)
{
$contentType = $response->getHeaderLine('Content-Type');
$contents = $response->getBody()->getContents();
if (false !== stripos($contentType, 'json') || stripos($contentType, 'javascript')) {
return json_decode($contents, true);
} elseif (false !== stripos($contentType, 'xml')) {
return json_decode(json_encode(simplexml_load_string($contents, 'SimpleXMLElement', LIBXML_NOCDATA), JSON_UNESCAPED_UNICODE), true);
}
return $contents;
}
}

View File

@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Yansongda\Supports\Traits;
use RuntimeException;
trait Serializable
{
/**
* toJson.
*
* @author yansongda <me@yansongda.cn>
*
* @return string
*/
public function toJson()
{
return $this->serialize();
}
/**
* Specify data which should be serialized to JSON.
*
* @see https://php.net/manual/en/jsonserializable.jsonserialize.php
*
* @return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource
*
* @since 5.4.0
*/
public function jsonSerialize()
{
if (method_exists($this, 'toArray')) {
return $this->toArray();
}
return [];
}
/**
* String representation of object.
*
* @see https://php.net/manual/en/serializable.serialize.php
*
* @return string the string representation of the object or null
*
* @since 5.1.0
*/
public function serialize()
{
if (method_exists($this, 'toArray')) {
return json_encode($this->toArray());
}
return json_encode([]);
}
/**
* Constructs the object.
*
* @see https://php.net/manual/en/serializable.unserialize.php
*
* @param string $serialized <p>
* The string representation of the object.
* </p>
*
* @since 5.1.0
*/
public function unserialize($serialized)
{
$data = json_decode($serialized, true);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new RuntimeException('Invalid Json Format');
}
foreach ($data as $key => $item) {
if (method_exists($this, 'set')) {
$this->set($key, $item);
}
}
}
}

View File

@@ -0,0 +1,147 @@
<?php
namespace Yansongda\Supports\Traits;
use Predis\Client;
/**
* Trait ShouldThrottle.
*
* @property Client $redis
*/
trait ShouldThrottle
{
/**
* _throttle.
*
* @var array
*/
protected $_throttle = [
'limit' => 60,
'period' => 60,
'count' => 0,
'reset_time' => 0,
];
/**
* isThrottled.
*
* @author yansongda <me@yansongda.cn>
*
* @param string $key
* @param int $limit
* @param int $period
* @param bool $auto_add
*
* @return bool
*/
public function isThrottled($key, $limit = 60, $period = 60, $auto_add = false)
{
if (-1 === $limit) {
return false;
}
$now = microtime(true) * 1000;
$this->redis->zremrangebyscore($key, 0, $now - $period * 1000);
$this->_throttle = [
'limit' => $limit,
'period' => $period,
'count' => $this->getThrottleCounts($key, $period),
'reset_time' => $this->getThrottleResetTime($key, $now),
];
if ($this->_throttle['count'] < $limit) {
if ($auto_add) {
$this->throttleAdd($key, $period);
}
return false;
}
return true;
}
/**
* 限流 + 1.
*
* @author yansongda <me@yansongda.cn>
*
* @param string $key
* @param int $period
*/
public function throttleAdd($key, $period = 60)
{
$now = microtime(true) * 1000;
$this->redis->zadd($key, [$now => $now]);
$this->redis->expire($key, $period * 2);
}
/**
* getResetTime.
*
* @author yansongda <me@yansongda.cn>
*
* @param $key
* @param $now
*
* @return int
*/
public function getThrottleResetTime($key, $now)
{
$data = $this->redis->zrangebyscore(
$key,
$now - $this->_throttle['period'] * 1000,
$now,
['limit' => [0, 1]]
);
if (0 === count($data)) {
return $this->_throttle['reset_time'] = time() + $this->_throttle['period'];
}
return intval($data[0] / 1000) + $this->_throttle['period'];
}
/**
* 获取限流相关信息.
*
* @author yansongda <me@yansongda.cn>
*
* @param string|null $key
* @param mixed|null $default
*
* @return array|null
*/
public function getThrottleInfo($key = null, $default = null)
{
if (is_null($key)) {
return $this->_throttle;
}
if (isset($this->_throttle[$key])) {
return $this->_throttle[$key];
}
return $default;
}
/**
* 获取已使用次数.
*
* @author yansongda <me@yansongda.cn>
*
* @param string $key
* @param int $period
*
* @return string
*/
public function getThrottleCounts($key, $period = 60)
{
$now = microtime(true) * 1000;
return $this->redis->zcount($key, $now - $period * 1000, $now);
}
}