Skip to content

Commit

Permalink
use __callStatic for legacy enum cases
Browse files Browse the repository at this point in the history
  • Loading branch information
klkvsk committed Apr 7, 2023
1 parent 451a744 commit 8b45e6f
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 51 deletions.
68 changes: 33 additions & 35 deletions example/php7.4/Genre.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,29 @@
*
* ---
*
* Readonly properties:
* @property-read string $name
* @property-read string $value
*
* Cases:
* @method static Genre ROMANCE
* @method static Genre COMEDY
* @method static Genre DRAMA
* @method static Genre NON_FICTION
* @method static Genre SCIENTIFIC_WORK
*/
final class Genre implements \JsonSerializable
{
private static ?array $map;
private static array $instances = [];

private static array $cases = [
'ROMANCE' => 'romance',
'COMEDY' => 'comedy',
'DRAMA' => 'drama',
'NON_FICTION' => 'non-fiction',
'SCIENTIFIC_WORK' => 'scientific-work',
];

private string $name;
private string $value;

Expand All @@ -34,13 +51,7 @@ private function __construct(string $name, string $value)
*/
public static function cases(): array
{
return self::$map = self::$map ?? [
new self('ROMANCE', 'romance'),
new self('COMEDY', 'comedy'),
new self('DRAMA', 'drama'),
new self('NON_FICTION', 'non-fiction'),
new self('SCIENTIFIC_WORK', 'scientific-work'),
];
return [self::ROMANCE(), self::COMEDY(), self::DRAMA(), self::NON_FICTION(), self::SCIENTIFIC_WORK()];
}

public function __get($propertyName)
Expand All @@ -56,10 +67,22 @@ public function __get($propertyName)
}
}

public static function __callStatic($name, $args)
{
$instance = self::$instances[$name] ?? null;
if ($instance === null) {
if (!array_key_exists($name, self::$cases)) {
throw new \ValueError("unknown case '$name'");
}
self::$instances[$name] = $instance = new self($name, self::$cases[$name]);
}
return $instance;
}

public static function tryFrom(string $value): ?self
{
$cases = self::cases();
return $cases[$value] ?? null;
$case = array_search($value, self::$cases, true);
return $case ? self::$case() : null;
}

public static function from(string $value): self
Expand All @@ -74,31 +97,6 @@ public static function from(string $value): self
return $case;
}

public static function ROMANCE(): self
{
return self::from('romance');
}

public static function COMEDY(): self
{
return self::from('comedy');
}

public static function DRAMA(): self
{
return self::from('drama');
}

public static function NON_FICTION(): self
{
return self::from('non-fiction');
}

public static function SCIENTIFIC_WORK(): self
{
return self::from('scientific-work');
}

public function jsonSerialize(): string
{
return $this->value;
Expand Down
49 changes: 33 additions & 16 deletions src/Generator/Builder/EnumLegacyBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,24 @@ public function build(Enum $enum, PhpNamespace $ns): EnumType|ClassType
$class = $ns->addClass($enum->getShortName())->setFinal();

$class
->addComment('Readonly properties:')
->addComment("@property-read string \$name")
->addComment("@property-read {$enum->getBackedType()} \$value");
->addComment("@property-read {$enum->getBackedType()} \$value")
->addComment("")
->addComment("Cases:");

$class->addProperty('map')

$class->addProperty('instances')
->setStatic()
->setPrivate()
->setNullable()
->setType('array');
->setType('array')
->setValue([]);

$class->addProperty('cases')
->setStatic()
->setPrivate()
->setType('array')
->setValue($enum->getCases());

$class->addProperty('name')
->setPrivate()
Expand Down Expand Up @@ -63,7 +73,20 @@ public function build(Enum $enum, PhpNamespace $ns): EnumType|ClassType
->addBody(' return null;')
->addBody('}');

// ::tryFrom(value)
$class
->addMethod('__callStatic')
->setParameters([ new Parameter('name'), new Parameter('args') ])
->setStatic()
->setPublic()
->addBody('$instance = self::$instances[$name] ?? null;')
->addBody('if ($instance === null) {')
->addBody(' if (!array_key_exists($name, self::$cases)) {')
->addBody(' throw new \ValueError("unknown case \'$name\'");')
->addBody(' }')
->addBody(' self::$instances[$name] = $instance = new self($name, self::$cases[$name]);')
->addBody('}')
->addBody('return $instance;');

$class->addMethod('tryFrom')
->setStatic()
->setPublic()
Expand All @@ -72,10 +95,9 @@ public function build(Enum $enum, PhpNamespace $ns): EnumType|ClassType
->setParameters([
(new Parameter('value'))->setType($enum->getBackedType())
])
->addBody('$cases = self::cases();')
->addBody('return $cases[$value] ?? null;');
->addBody('$case = array_search($value, self::$cases, true);')
->addBody('return $case ? self::$case() : null;');

// ::from($value)
$class->addMethod('from')
->setStatic()
->setPublic()
Expand All @@ -94,16 +116,11 @@ public function build(Enum $enum, PhpNamespace $ns): EnumType|ClassType

$casesMap = [];
foreach ($enum->getCases() as $case => $value) {
$class->addMethod($case)
->setStatic()
->setPublic()
->setReturnType('self')
->addBody('return self::from(?);', [$value]);

$casesMap[] = new Literal('new self(?, ?)', [$case, $value]);
$class->addComment("@method static {$enum->getShortName()} $case");
$casesMap[] = new Literal("self::$case()");
}

$casesMethod->addBody('return self::$map = self::$map \?\? ?;', [$casesMap]);
$casesMethod->addBody('return ?;', [$casesMap]);

$class->addImplement('\\JsonSerializable');
$class->addMethod('jsonSerialize')
Expand Down

0 comments on commit 8b45e6f

Please sign in to comment.