add chain and stopwatch helper functions (#99)

* add chain helper function

* add stopwatch helper function
This commit is contained in:
sunxyw
2022-04-15 23:10:29 +08:00
committed by GitHub
parent ea64b40011
commit 97face2406
2 changed files with 138 additions and 0 deletions

View File

@@ -627,6 +627,101 @@ function zm_internal_errcode($code): string
return "[ErrCode:{$code}] ";
}
if (!function_exists('chain')) {
define('CARRY', '{carry}');
/**
* 链式调用对象方法
*
* 如需使用上一步的返回值作为参数,请使用 CARRY 常量替换对应的参数值
*
* @param object $object 需要进行链式调用的对象
* @return object 链式操作对象,可当成传入的对象使用
*/
function chain(object $object): object
{
return new class($object) {
/**
* 最后一次执行的方法的返回值
*
* @var mixed
*/
protected $return;
/**
* 需要进行链式调用的对象
*
* @var object
*/
protected $wrapped;
/**
* 构造链式调用匿名类
*/
public function __construct(object $object)
{
$this->wrapped = $object;
}
/**
* 代理所有调用
*/
public function __call(string $name, array $arguments)
{
if (($index = array_search(CARRY, $arguments, true)) !== false) {
$arguments[$index] = $this->return;
}
$this->return = $this->wrapped->{$name}(...$arguments);
return $this;
}
/**
* 返回最后执行结果
*/
public function __toString()
{
return (string) $this->return;
}
/**
* 允许调用最后返回结果
*/
public function __invoke()
{
return $this->return;
}
/**
* 使用链式操作对象作为参数,执行回调
*/
public function tap(callable $callback): self
{
$callback($this->wrapped);
return $this;
}
};
}
}
if (!function_exists('stopwatch')) {
/**
* 执行回调函数并返回平均执行耗时
*
* @param int $times 执行次数
* @return float 平均执行耗时
*/
function stopwatch(callable $callback, int $times = 1): float
{
$total = 0;
for ($i = 0; $i < $times; ++$i) {
$start = microtime(true);
$callback();
$total += microtime(true) - $start;
}
return $total / $times;
}
}
/**
* 将可能为数组的参数转换为字符串
*

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace Tests\ZM;
use PHPUnit\Framework\TestCase;
/**
* @internal
*/
class GlobalFunctionsTest extends TestCase
{
public function testChain(): void
{
$mock = $this->getMockBuilder(\stdClass::class)
->addMethods(['foo', 'bar', 'baz'])
->getMock();
$mock->expects($this->once())
->method('foo')
->willReturn('foo');
$mock->expects($this->once())
->method('bar')
->with('foo')
->willReturn('bar');
$mock->expects($this->once())
->method('baz')
->with('bar')
->willReturn('baz');
$result = chain($mock)->foo()->bar(CARRY)->baz(CARRY);
$this->assertEquals('baz', $result);
}
public function testStopwatch(): void
{
$time = stopwatch(static function () {
usleep(10000);
});
$this->assertLessThan(0.1, $time);
}
}