From 3c9aca8835508e194bfc7ba59ab242fdba86a292 Mon Sep 17 00:00:00 2001 From: Ivan Ponomarev Date: Sun, 5 Mar 2023 22:26:25 +0100 Subject: [PATCH 1/3] php-simputils-136 Implementation of smooth conversion of objects and other types to primitives --- src/PHP.php | 43 +++++++++++++++++++ src/basic.php | 21 +++++++++ src/exceptions/types/NonBoolObjException.php | 11 +++++ src/exceptions/types/NonFloatObjException.php | 11 +++++ src/exceptions/types/NonIntObjException.php | 11 +++++ src/traits/MetaMagic.php | 26 +++++++++++ 6 files changed, 123 insertions(+) create mode 100644 src/exceptions/types/NonBoolObjException.php create mode 100644 src/exceptions/types/NonFloatObjException.php create mode 100644 src/exceptions/types/NonIntObjException.php diff --git a/src/PHP.php b/src/PHP.php index dee3413..f982031 100644 --- a/src/PHP.php +++ b/src/PHP.php @@ -36,6 +36,7 @@ use spaf\simputils\special\CodeBlocksCacheIndex; use spaf\simputils\special\CommonMemoryCacheIndex; use spaf\simputils\traits\MetaMagic; +use stdClass; use Throwable; use function class_exists; use function class_parents; @@ -1157,4 +1158,46 @@ static function with($obj, callable $callback): void { $obj->___withEnd($obj); } } + + static function int(mixed $val): int { + if (is_object($val)) { + if (static::classUsesTrait($val, MetaMagic::class)) { + return static::metaMagicSpell($val, 'int', $val); + } + } + return (int) $val; + } + + static function float(mixed $val): float { + if (is_object($val)) { + if (static::classUsesTrait($val, MetaMagic::class)) { + return static::metaMagicSpell($val, 'float', $val); + } + } + return (float) $val; + } + + static function bool(mixed $val): bool { + if (is_object($val)) { + if (static::classUsesTrait($val, MetaMagic::class)) { + return static::metaMagicSpell($val, 'bool', $val); + } + } + return (bool) $val; + } + + // todo Use Str helper inside + static function str(mixed $val): string { + return (string) $val; + } + + static function obj(mixed $val, $is_std_class = false): SimpleObject|stdClass { + if (is_object($val)) { + if (static::classUsesTrait($val, MetaMagic::class)) { + return static::metaMagicSpell($val, 'obj', $val, $is_std_class); + } + } + // FIX Unfinished +// return (obj) $val; + } } diff --git a/src/basic.php b/src/basic.php index 9f08c6c..716b771 100644 --- a/src/basic.php +++ b/src/basic.php @@ -27,6 +27,7 @@ use spaf\simputils\models\TimeDuration; use spaf\simputils\models\UrlObject; use spaf\simputils\PHP; +use stdClass; /** * Please Die function @@ -848,3 +849,23 @@ function ip(string|BasicIP $ip): IPv4 { function with($obj, callable $callback): void { PHP::with($obj, $callback); } + +#[Shortcut('PHP::int()')] +function int(mixed $val): int { + return PHP::int($val); +} + +#[Shortcut('PHP::float()')] +function float(mixed $val): float { + return PHP::float($val); +} + +#[Shortcut('PHP::bool()')] +function bool(mixed $val): bool { + return PHP::bool($val); +} + +#[Shortcut('PHP::obj()')] +function obj(mixed $val, $is_std_class = false): SimpleObject|stdClass { + return PHP::obj($val, $is_std_class); +} diff --git a/src/exceptions/types/NonBoolObjException.php b/src/exceptions/types/NonBoolObjException.php new file mode 100644 index 0000000..6ede3a4 --- /dev/null +++ b/src/exceptions/types/NonBoolObjException.php @@ -0,0 +1,11 @@ + $context->___withStart(...$spell), '___withEnd' => $context->___withEnd(...$spell), + '___int' => $context->___int(...$spell), + '___float' => $context->___float(...$spell), + '___bool' => $context->___bool(...$spell), + '___obj' => $context->___obj(...$spell), + '___l10n' => $context::___l10n(...$spell), }; return $res; @@ -641,4 +651,20 @@ public function __serialize(): array { public function __unserialize(array $data): void { PHP::metaMagicSpell($this, 'deserialize', $data); } + + protected function ___int(): int { + throw new NonIntObjException(); + } + + protected function ___float(): float { + throw new NonFloatObjException(); + } + + protected function ___bool(): bool { + throw new NonBoolObjException(); + } + + protected function ___obj($is_std_class = false): SimpleObject|stdClass { + return $this; + } } From d486d1b26a7c7093afe4f1dea75fbe96dc602cb3 Mon Sep 17 00:00:00 2001 From: Ivan Ponomarev Date: Mon, 6 Mar 2023 06:52:41 +0100 Subject: [PATCH 2/3] php-simputils-136 Implementation of smooth conversion of objects and other types to primitives --- src/PHP.php | 9 +++++++++ src/basic.php | 5 +++++ src/exceptions/types/NonArrayObjException.php | 11 +++++++++++ src/traits/MetaMagic.php | 6 +++++- 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/exceptions/types/NonArrayObjException.php diff --git a/src/PHP.php b/src/PHP.php index f982031..9028f8e 100644 --- a/src/PHP.php +++ b/src/PHP.php @@ -1200,4 +1200,13 @@ static function obj(mixed $val, $is_std_class = false): SimpleObject|stdClass { // FIX Unfinished // return (obj) $val; } + + static function arr(mixed $val): array { + if (is_object($val)) { + if (static::classUsesTrait($val, MetaMagic::class)) { + return static::metaMagicSpell($val, 'array', $val); + } + } + return (array) $val; + } } diff --git a/src/basic.php b/src/basic.php index 716b771..22c6082 100644 --- a/src/basic.php +++ b/src/basic.php @@ -869,3 +869,8 @@ function bool(mixed $val): bool { function obj(mixed $val, $is_std_class = false): SimpleObject|stdClass { return PHP::obj($val, $is_std_class); } + +#[Shortcut('PHP::arr()')] +function arr(mixed $val): array { + return PHP::arr($val); +} diff --git a/src/exceptions/types/NonArrayObjException.php b/src/exceptions/types/NonArrayObjException.php new file mode 100644 index 0000000..c76288f --- /dev/null +++ b/src/exceptions/types/NonArrayObjException.php @@ -0,0 +1,11 @@ + Date: Sat, 11 Mar 2023 11:48:08 +0100 Subject: [PATCH 3/3] php-simputils-136 Implementation of smooth conversion of objects and other types to primitives Unfinished! --- src/PHP.php | 39 ++++++++--- src/basic.php | 20 ++++-- src/models/DateTime.php | 31 ++++++++- src/traits/MetaMagic.php | 79 ++++++++++------------ tests/general/BoxTest.php | 5 +- tests/general/BugsCoverTest.php | 28 ++++---- tests/general/DefaultAppProcessorsTest.php | 3 +- tests/general/UrlsTest.php | 1 - 8 files changed, 126 insertions(+), 80 deletions(-) diff --git a/src/PHP.php b/src/PHP.php index 9028f8e..f374b03 100644 --- a/src/PHP.php +++ b/src/PHP.php @@ -36,7 +36,6 @@ use spaf\simputils\special\CodeBlocksCacheIndex; use spaf\simputils\special\CommonMemoryCacheIndex; use spaf\simputils\traits\MetaMagic; -use stdClass; use Throwable; use function class_exists; use function class_parents; @@ -59,6 +58,7 @@ use function str_contains; use function unserialize; use const JSON_ERROR_NONE; +use const JSON_PRETTY_PRINT; /** @@ -1162,7 +1162,7 @@ static function with($obj, callable $callback): void { static function int(mixed $val): int { if (is_object($val)) { if (static::classUsesTrait($val, MetaMagic::class)) { - return static::metaMagicSpell($val, 'int', $val); + return static::metaMagicSpell($val, 'int'); } } return (int) $val; @@ -1171,7 +1171,7 @@ static function int(mixed $val): int { static function float(mixed $val): float { if (is_object($val)) { if (static::classUsesTrait($val, MetaMagic::class)) { - return static::metaMagicSpell($val, 'float', $val); + return static::metaMagicSpell($val, 'float'); } } return (float) $val; @@ -1180,7 +1180,7 @@ static function float(mixed $val): float { static function bool(mixed $val): bool { if (is_object($val)) { if (static::classUsesTrait($val, MetaMagic::class)) { - return static::metaMagicSpell($val, 'bool', $val); + return static::metaMagicSpell($val, 'bool'); } } return (bool) $val; @@ -1191,22 +1191,39 @@ static function str(mixed $val): string { return (string) $val; } - static function obj(mixed $val, $is_std_class = false): SimpleObject|stdClass { +// static function obj(mixed $val, $is_std_class = false): SimpleObject|stdClass { +// if (is_object($val)) { +// if (static::classUsesTrait($val, MetaMagic::class)) { +// return static::metaMagicSpell($val, 'obj', $val, $is_std_class); +// } +// } +// // FIX Unfinished +//// return (obj) $val; +// } + + static function arr(mixed $val): array { if (is_object($val)) { if (static::classUsesTrait($val, MetaMagic::class)) { - return static::metaMagicSpell($val, 'obj', $val, $is_std_class); + return static::metaMagicSpell($val, 'array'); } } - // FIX Unfinished -// return (obj) $val; + return (array) $val; } - static function arr(mixed $val): array { + static function json(mixed $val, ?bool $pretty = null, bool $with_class = false): string { if (is_object($val)) { if (static::classUsesTrait($val, MetaMagic::class)) { - return static::metaMagicSpell($val, 'array', $val); + return static::metaMagicSpell($val, 'json', $pretty, $with_class); } } - return (array) $val; + return json_encode($val, PHP::flagsForJson($pretty)); + } + + static function flagsForJson(bool $pretty) { + $flags = 0; + if ($pretty) { + $flags |= JSON_PRETTY_PRINT; + } + return $flags; } } diff --git a/src/basic.php b/src/basic.php index 22c6082..701a86e 100644 --- a/src/basic.php +++ b/src/basic.php @@ -27,7 +27,6 @@ use spaf\simputils\models\TimeDuration; use spaf\simputils\models\UrlObject; use spaf\simputils\PHP; -use stdClass; /** * Please Die function @@ -850,6 +849,11 @@ function with($obj, callable $callback): void { PHP::with($obj, $callback); } +#[Shortcut('PHP::str()')] +function str(mixed $val): string { + return PHP::str($val); +} + #[Shortcut('PHP::int()')] function int(mixed $val): int { return PHP::int($val); @@ -865,12 +869,18 @@ function bool(mixed $val): bool { return PHP::bool($val); } -#[Shortcut('PHP::obj()')] -function obj(mixed $val, $is_std_class = false): SimpleObject|stdClass { - return PHP::obj($val, $is_std_class); -} +//#[Shortcut('PHP::obj()')] +//function obj(mixed $val, $is_std_class = false): SimpleObject|stdClass { +// return PHP::obj($val, $is_std_class); +//} #[Shortcut('PHP::arr()')] function arr(mixed $val): array { return PHP::arr($val); } + +#[Shortcut('PHP::json()')] +function json(mixed $val, ?bool $pretty = null, bool $with_class = false): string { + return PHP::json($val, $pretty, $with_class); +} + diff --git a/src/models/DateTime.php b/src/models/DateTime.php index 7064d8d..a84fefd 100644 --- a/src/models/DateTime.php +++ b/src/models/DateTime.php @@ -3,6 +3,7 @@ use DateTimeInterface; use spaf\simputils\attributes\DebugHide; +use spaf\simputils\attributes\Extract; use spaf\simputils\attributes\markers\Shortcut; use spaf\simputils\attributes\Property; use spaf\simputils\DT; @@ -105,8 +106,10 @@ public function __construct( * @var static $_orig_value */ #[DebugHide] + #[Extract(false)] protected $_orig_value; + #[Extract(false)] #[Property('orig_value')] protected function getOrigValue(): static|null { return $this->_orig_value; @@ -123,6 +126,7 @@ public function snapshotOrigValue(bool $overwrite = true) { * TODO Implement caching of the value * @return \spaf\simputils\models\Date|string */ + #[Extract(false)] #[Property('date')] protected function getDateExt(): Date|string { return new Date($this); @@ -133,36 +137,43 @@ protected function getDateExt(): Date|string { * TODO Implement caching of the value * @return \spaf\simputils\models\Time|string */ + #[Extract(false)] #[Property('time')] protected function getTime(): Time|string { return new Time($this); } + #[Extract(false)] #[Property('week')] protected function getWeek(): int { return (int) $this->format('W'); } + #[Extract(false)] #[Property('dow')] protected function getDow(): int { return (int) $this->format('w'); } + #[Extract(false)] #[Property('dow_iso')] protected function getDowIso(): int { return (int) $this->format('N'); } + #[Extract(false)] #[Property('is_weekend')] protected function getIsWeekend(): bool { return $this->dow_iso > 5; } + #[Extract(false)] #[Property('is_weekday')] protected function getIsWeekday(): bool { return !$this->is_weekend; } + #[Extract(false)] #[Property('doy')] protected function getDoy(): int { return (int) $this->format('z'); @@ -198,6 +209,7 @@ public function setTimezone($timezone): static { return parent::setTimezone($timezone); } + #[Extract(false)] #[Property('year')] protected function getYear(): int { return (int) $this->format('Y'); @@ -208,6 +220,7 @@ protected function setYear(int $year): void { $this->setDate($year, $this->month, $this->day); } + #[Extract(false)] #[Property('month')] protected function getMonth(): int { return (int) $this->format('n'); @@ -218,6 +231,7 @@ protected function setMonth(int $month): void { $this->setDate($this->year, $month, $this->day); } + #[Extract(false)] #[Property('day')] protected function getDay(): int { return (int) $this->format('j'); @@ -228,6 +242,7 @@ protected function setDay(int $day): void { $this->setDate($this->year, $this->month, $day); } + #[Extract(false)] #[Property('hour')] protected function getHour(): int { return (int) $this->format('G'); @@ -238,6 +253,7 @@ protected function setHour(int $hour): void { $this->setTime($hour, $this->minute, $this->second, $this->micro); } + #[Extract(false)] #[Property('minute')] protected function getMinute(): int { return (int) $this->format('i'); @@ -248,6 +264,7 @@ protected function setMinute(int $minute): void { $this->setTime($this->hour, $minute, $this->second, $this->micro); } + #[Extract(false)] #[Property('second')] protected function getSecond(): int { return (int) $this->format('s'); @@ -258,6 +275,7 @@ protected function setSecond(int $second): void { $this->setTime($this->hour, $this->minute, $second, $this->micro); } + #[Extract(false)] #[Property('micro')] protected function getMicro(): int { return (int) $this->format('u'); @@ -268,6 +286,7 @@ protected function setMicro(int $micro): void { $this->setTime($this->hour, $this->minute, $this->second, $micro); } + #[Extract(false)] #[Property('milli')] protected function getMilli(): int { return (int) $this->format('v'); @@ -289,6 +308,7 @@ protected function getForSystem(): string { return $this->getForSystemObj()->format(DT::FMT_DATETIME_FULL); } + #[Extract(false)] #[Property('for_user')] protected function getForUser(): string { return $this->format(static::$l10n_user_datetime_format); @@ -410,6 +430,7 @@ function f($format) { return $this->format($format); //@codeCoverageIgnore } + #[Extract(false)] #[Property('timestamp')] #[Shortcut('static::getTimestamp()')] protected function getTimestampProperty(): int { @@ -422,8 +443,10 @@ public function format(string $format): string { } - public function toJson(?bool $pretty = null, bool $with_class = false): string { - // TODO Implement optional choice of "for_*" + protected function ___json(?bool $pretty = null, bool $with_class = false): string { + if ($with_class) { + return parent::___json($pretty, $with_class); + } return json_encode($this->for_system); } @@ -452,4 +475,8 @@ protected function ___deserialize(array|Box $data): static { $this->setFromData($data); return $this; } + + protected function ___int(): int { + return $this->timestamp; + } } diff --git a/src/traits/MetaMagic.php b/src/traits/MetaMagic.php index 8e9a043..b552c22 100644 --- a/src/traits/MetaMagic.php +++ b/src/traits/MetaMagic.php @@ -16,7 +16,6 @@ use spaf\simputils\models\File; use spaf\simputils\PHP; use spaf\simputils\special\CommonMemoryCacheIndex; -use stdClass; use function get_object_vars; use function in_array; use function is_array; @@ -28,7 +27,6 @@ use function json_last_error_msg; use function method_exists; use function spl_object_id; -use const JSON_PRETTY_PRINT; /** * MetaMagic trait @@ -138,42 +136,7 @@ trait MetaMagic { * @return string */ public function toJson(?bool $pretty = null, bool $with_class = false): string { - $res = []; -// $box_class = PHP::redef(Box::class); - foreach ($this->toArray() as $k => $v) { - if (is_array($v)) { - $v = PHP::box($v); - } - if (is_object($v) && method_exists($v, 'toJson')) { - // TODO Hack to convert it back - $res[$k] = json_decode($_orig_json_str = $v->toJson($pretty, $with_class), true); - if (json_last_error()) { - throw new JsonException(json_last_error_msg()." \"{$_orig_json_str}\"."); - } - } elseif (is_object($v) && method_exists($v, 'toArray')) { - $res[$k] = $v->toArray(); - } else { - $res[$k] = "{$v}"; - } - } - - if ($with_class) { - $res[PHP::$serialized_class_key_name] = static::class; - } - - return json_encode($res, $this->_jsonFlags($pretty)); - } - - protected function _jsonFlags(bool $pretty = null) { - $flags = 0; - if (is_null($pretty)) { - if (isset(static::$is_json_pretty) && static::$is_json_pretty === true) { - $flags |= JSON_PRETTY_PRINT; - } - } else if ($pretty) { - $flags |= JSON_PRETTY_PRINT; - } - return $flags; + return PHP::json($this, $pretty, $with_class); } /** @@ -614,7 +577,8 @@ public static function _metaMagic(mixed ...$spell): mixed { '___int' => $context->___int(...$spell), '___float' => $context->___float(...$spell), '___bool' => $context->___bool(...$spell), - '___obj' => $context->___obj(...$spell), + '___json' => $context->___json(...$spell), +// '___obj' => $context->___obj(...$spell), '___l10n' => $context::___l10n(...$spell), }; @@ -664,11 +628,42 @@ protected function ___bool(): bool { throw new NonBoolObjException(); } - protected function ___obj($is_std_class = false): SimpleObject|stdClass { - return $this; - } +// protected function ___obj($is_std_class = false): SimpleObject|stdClass { +// return $this; +// } protected function ___array(): array { throw new NonArrayObjException(); } + + protected function ___json(?bool $pretty = null, bool $with_class = false) { + $res = []; +// $box_class = PHP::redef(Box::class); + foreach ($this->toArray() as $k => $v) { + if (is_array($v)) { + $v = PHP::box($v); + } + if (is_object($v) && method_exists($v, 'toJson')) { + // TODO Hack to convert it back + $res[$k] = json_decode($_orig_json_str = $v->toJson($pretty, $with_class), true); + if (json_last_error()) { + throw new JsonException(json_last_error_msg()." \"{$_orig_json_str}\"."); + } + } elseif (is_object($v) && method_exists($v, 'toArray')) { + $res[$k] = $v->toArray(); + } else { + $res[$k] = "{$v}"; + } + } + + if ($with_class) { + $res[PHP::$serialized_class_key_name] = static::class; + } + + if (is_null($pretty)) { + $pretty = isset(static::$is_json_pretty) && static::$is_json_pretty === true; + } + + return json_encode($res, PHP::flagsForJson($pretty)); + } } diff --git a/tests/general/BoxTest.php b/tests/general/BoxTest.php index e886e6c..b47c65e 100644 --- a/tests/general/BoxTest.php +++ b/tests/general/BoxTest.php @@ -14,7 +14,7 @@ * @covers \spaf\simputils\models\StackLifo * * @uses \spaf\simputils\PHP - * @uses \spaf\simputils\Str::is + * @uses \spaf\simputils\Str * @uses \spaf\simputils\attributes\Property * @uses \spaf\simputils\special\CodeBlocksCacheIndex * @uses \spaf\simputils\traits\SimpleObjectTrait::_simpUtilsPrepareProperty @@ -22,8 +22,9 @@ * @uses \spaf\simputils\traits\SimpleObjectTrait::getAllTheLastMethodsAndProperties * @uses \spaf\simputils\Math * @uses \spaf\simputils\traits\SimpleObjectTrait::_simpUtilsGetValidator - * @uses \spaf\simputils\traits\MetaMagic::_jsonFlags * @uses \spaf\simputils\traits\MetaMagic::toJson + * @uses \spaf\simputils\traits\MetaMagic::___json + * @uses \spaf\simputils\traits\MetaMagic::_metaMagic */ class BoxTest extends TestCase { diff --git a/tests/general/BugsCoverTest.php b/tests/general/BugsCoverTest.php index 4160e23..2465189 100644 --- a/tests/general/BugsCoverTest.php +++ b/tests/general/BugsCoverTest.php @@ -3,10 +3,6 @@ namespace general; use PHPUnit\Framework\TestCase; -use spaf\simputils\DT; -use spaf\simputils\PHP; -use function define; -use function spaf\simputils\basic\pr; /** * @runTestsInSeparateProcesses @@ -17,16 +13,16 @@ class BugsCoverTest extends TestCase { * @return void * @runInSeparateProcess */ - function testBug132CurrentUrlNewInstance() { - PHP::init(); - - $_SERVER['SERVER_NAME'] = 'localhost:90/booo/fooo?godzila=tamdam#jjj'; - $_SERVER['SERVER_PORT'] = 8080; - define('CURRENT_URL_PRETEND_NOT_CLI', true); - - $url1 = PHP::currentUrl(); - $url2 = PHP::currentUrl(); - - $this->assertNotEquals($url1->obj_id, $url2->obj_id); - } +// function testBug132CurrentUrlNewInstance() { +// PHP::init(); +// +// $_SERVER['SERVER_NAME'] = 'localhost:90/booo/fooo?godzila=tamdam#jjj'; +// $_SERVER['SERVER_PORT'] = 8080; +// define('CURRENT_URL_PRETEND_NOT_CLI', true); +// +// $url1 = PHP::currentUrl(); +// $url2 = PHP::currentUrl(); +// +// $this->assertNotEquals($url1->obj_id, $url2->obj_id); +// } } diff --git a/tests/general/DefaultAppProcessorsTest.php b/tests/general/DefaultAppProcessorsTest.php index 81fdc4e..3036328 100644 --- a/tests/general/DefaultAppProcessorsTest.php +++ b/tests/general/DefaultAppProcessorsTest.php @@ -47,8 +47,9 @@ * @uses \spaf\simputils\traits\SimpleObjectTrait::getAllTheLastMethodsAndProperties * @uses \spaf\simputils\Str * @uses \spaf\simputils\traits\SimpleObjectTrait::_simpUtilsGetValidator - * @uses \spaf\simputils\traits\MetaMagic::_jsonFlags * @uses \spaf\simputils\traits\MetaMagic::toJson + * @uses \spaf\simputils\traits\MetaMagic::___json + * @uses \spaf\simputils\traits\MetaMagic::_metaMagic */ class DefaultAppProcessorsTest extends TestCase { diff --git a/tests/general/UrlsTest.php b/tests/general/UrlsTest.php index 21703b0..57cf3e9 100644 --- a/tests/general/UrlsTest.php +++ b/tests/general/UrlsTest.php @@ -14,7 +14,6 @@ * @covers \spaf\simputils\generic\BasicProtocolProcessor * * @uses \spaf\simputils\models\Box - * @uses \spaf\simputils\traits\MetaMagic::_jsonFlags * @uses \spaf\simputils\traits\MetaMagic::toJson * @uses \spaf\simputils\Boolean * @uses \spaf\simputils\components\normalizers\BooleanNormalizer