/** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Get/Exceptions/PatternFailed.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic\Get\Exceptions; use Exception; class PatternFailed extends Exception {} /** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Get/Exceptions/FallbackFailed.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic\Get\Exceptions; use Exception; class FallbackFailed extends Exception {} /** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Get/Get.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic; use Attribute; use ARUNOX\API\PHP; #[Attribute( Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE )] class Get { use PHP\Attributes\Magic\Get\Helper; /* ### VARIABLES ################################################ # */ /* ### PROTECTED FUNCTIONS ###################################### # */ /* ### MAGIC FUNCTIONS ########################################## # */ public function __construct( protected null|string $match = NULL, protected bool $fallback = FALSE, protected int $priority = 10 ){} } /** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Get/Helper.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic\Get; use ARUNOX\API\PHP; use ReflectionClass; use ReflectionMethod; trait Helper { /* ### VARIABLES ################################################ # */ protected static array $__CACHED_GETTER = []; /* ### PUBLIC STATIC FUNCTIONS ################################## # */ public static function getMagicGetter() : array { $class = static::class; if( !isset( static::$__CACHED_GETTER[ $class ] ) ) { static::$__CACHED_GETTER[ $class ] = static::resolveMagicGettersFromClass(); } return static::$__CACHED_GETTER[ $class ]; } /* ### PRIVATE STATIC FUNCTIONS ################################# # */ private static function resolveMagicGettersFromClass() : array { $ref = new ReflectionClass( static::class ); $result = [ "exact" => [], "pattern" => [], "fallback" => [], ]; foreach( $ref->getMethods(ReflectionMethod::IS_PUBLIC ) as $method ) { foreach( $method->getAttributes(PHP\Attributes\Magic\Get::class ) as $attr ) { $meta = $attr->newInstance(); $target = $method->getName(); if( $meta->fallback || $meta->match === NULL || $meta->match === "*" ) { $result["fallback"][ $meta->priority ][] = $target; continue; } if( @preg_match("/^{$meta->match}$/", "" ) !== FALSE ) { $result["pattern"][ $meta->priority ][] = [ "/^{$meta->match}$/", $target ]; continue; } $result["exact"][ $meta->priority ][ $meta->match ] = $target; } } foreach( $result as &$type ) { ksort( $type ); $type = array_reduce_recursive( $type ); $type = array_values( $type ); } return $result; } /* ### MAGIC FUNCTIONS ########################################## # */ public function __get( string $name ) : mixed { $map = self::getMagicGetter(); // 1. exact if( isset( $map["exact"][ $name ] ) ) { return $this->{$map["exact"][ $name ]}(); } // 2. pattern foreach( $map["pattern"] as [ $regex, $method ]) { if( preg_match( $regex, $name ) ) { try { return $this->{$method}( $name ); } catch( Exceptions\PatternFailed $e ) {} } } // 3. fallback foreach( $map["fallback"] as $method ) { try { return $this->{$method}( $name ); } catch( Exceptions\FallbackFailed $e ) {} } // 4. method getXyz() if( method_exists( $this, "get{$name}" ) ) { return $this->{"get{$name}"}(); } // 5. property access if( property_exists( $this, $name ) ) { return $this->{$name}; } throw new \BadMethodCallException("Unbekannte dynamische Eigenschaft: {$name}"); } } /** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Call/Exceptions/PatternFailed.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic\Call\Exceptions; use Exception; class PatternFailed extends Exception {} /** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Call/Exceptions/FallbackFailed.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic\Call\Exceptions; use Exception; class FallbackFailed extends Exception {} /** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Call/Call.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic; use Attribute; use ARUNOX\API\PHP; #[Attribute( Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE )] class Call { use PHP\Attributes\Magic\Get\Helper; /* ### VARIABLES ################################################ # */ /* ### PROTECTED FUNCTIONS ###################################### # */ /* ### MAGIC FUNCTIONS ########################################## # */ public function __construct( protected null|string $match = NULL, protected bool $fallback = FALSE ){} } /** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Call/Helper.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic\Call; use ARUNOX\API\PHP; use ReflectionClass; use ReflectionMethod; trait Helper { /* ### VARIABLES ################################################ # */ protected static array $__CACHED_CALLER = []; /* ### PUBLIC STATIC FUNCTIONS ################################## # */ public static function getMagicCaller( bool $static = FALSE ) : array { $class = static::class; $type = $static ? "static" : "normal"; if( !isset( static::$__CACHED_CALLER[ $class ] ) ) { static::$__CACHED_CALLER[ $class ] = static::resolveMagicCallerFromClass(); } return static::$__CACHED_CALLER[ $class ][ $type ]; } /* ### PRIVATE STATIC FUNCTIONS ################################# # */ private static function resolveMagicCallerFromClass() : array { $ref = new ReflectionClass( static::class ); $result = [ "exact" => [], "pattern" => [], "fallback" => [], ]; $result = [ "static" => $result, "normal" => $result, ]; foreach( $ref->getMethods(ReflectionMethod::IS_PUBLIC ) as $method ) { foreach( $method->getAttributes(PHP\Attributes\Magic\Call::class ) as $attr ) { $meta = $attr->newInstance(); $target = $method->getName(); $type = $method->isStatic() ? "static" : "normal"; // show( $meta, $method, $type, $target ); if( $meta->fallback || $meta->match === NULL || $meta->match === "*" ) { $result[ $type ]["fallback"][] = $target; continue; } if( @preg_match("/^{$meta->match}$/", "" ) !== FALSE ) { $result[ $type ]["pattern"][] = [ "/^{$meta->match}$/", $target ]; continue; } $result[ $type ]["exact"][ $meta->match ] = $target; } } return $result; } /* ### MAGIC FUNCTIONS ########################################## # */ public function __call( string $name, array $args ) : mixed { $map = self::getMagicCaller(); // if( $name == "getIcon" ) show( $name, $args, $map, FALSE ); // 1. exact if( isset( $map["exact"][ $name ] ) ) { return $this->{$map["exact"][ $name ]}( ...$args ); } // 2. pattern foreach( $map["pattern"] as [ $regex, $method ]) { if( preg_match( $regex, $name, $matches ) ) { try { return $this->{$method}( $matches, ...$args ); } catch( Exceptions\PatternFailed $e ) {} } } // 3. fallback foreach( $map["fallback"] as $method ) { try { return $this->{$method}( $name, ...$args ); } catch( Exceptions\FallbackFailed $e ) {} } return NULL; // throw new \BadMethodCallException("Unbekannte dynamische Methode: {$name}"); } public static function __callStatic( string $name, array $args ) : mixed { $map = self::getMagicCaller( TRUE ); // show( static::class, FALSE ); // 1. exact if( isset( $map["exact"][ $name ] ) ) { return static::{$map["exact"][ $name ]}( ...$args ); } // 2. pattern foreach( $map["pattern"] as [ $regex, $method ]) { if( preg_match( $regex, $name, $matches ) ) { try { return static::{$method}( $matches, ...$args ); } catch( Exceptions\PatternFailed $e ) {} } } // 3. fallback foreach( $map["fallback"] as $method ) { try { return static::{$method}( $name, ...$args ); } catch( Exceptions\FallbackFailed $e ) {} } return NULL; // throw new \BadMethodCallException("Unbekannte dynamische Methode: {$name}"); } } /** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Set/Set.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic; use Attribute; use ARUNOX\API\PHP; #[Attribute( Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE )] class Set { use PHP\Attributes\Magic\Get\Helper; /* ### VARIABLES ################################################ # */ /* ### PROTECTED FUNCTIONS ###################################### # */ /* ### MAGIC FUNCTIONS ########################################## # */ public function __construct( protected null|string $match = NULL, protected bool $fallback = FALSE ){} } /** Datei: library/ARUNOX/API/PHP/Attributes/Magic/Set/Helper.php **/ * @copyright 2025 ARUNOX * @version 1.1.0 * * @since 1.0.0 File is created */ namespace ARUNOX\API\PHP\Attributes\Magic\Set; use ARUNOX\API\PHP; use ReflectionClass; use ReflectionMethod; trait Helper { /* ### VARIABLES ################################################ # */ protected static array $__CACHED_SETTER = []; /* ### PUBLIC STATIC FUNCTIONS ################################## # */ public static function getMagicSetter() : array { $class = static::class; if( !isset( static::$__CACHED_SETTER[ $class ] ) ) { static::$__CACHED_SETTER[ $class ] = static::resolveMagicSettersFromClass(); } return static::$__CACHED_SETTER[ $class ]; } /* ### PRIVATE STATIC FUNCTIONS ################################# # */ private static function resolveMagicSettersFromClass() : array { $ref = new ReflectionClass( static::class ); $result = [ "exact" => [], "pattern" => [], "fallback" => [], ]; foreach( $ref->getMethods(ReflectionMethod::IS_PUBLIC ) as $method ) { foreach( $method->getAttributes(PHP\Attributes\Magic\Set::class ) as $attr ) { $meta = $attr->newInstance(); $target = $method->getName(); if( $meta->fallback || $meta->match === NULL || $meta->match === "*" ) { $result["fallback"][] = $target; continue; } if( @preg_match("/^{$meta->match}$/", "" ) !== FALSE ) { $result["pattern"][] = [ "/^{$meta->match}$/", $target ]; continue; } $result["exact"][ $meta->match ] = $target; } } return $result; } /* ### MAGIC FUNCTIONS ########################################## # */ public function __set( string $name, mixed $value ) : void { $map = self::getMagicSetter(); // 1. exact if( isset( $map["exact"][ $name ] ) ) { // show( "Case 1", $map["exact"], $name, $value, FALSE ); $this->{$map["exact"][ $name ]}( $value ); return; } // 2. pattern foreach( $map["pattern"] as [ $regex, $method ]) { if( preg_match( $regex, $name ) ) { // show( "Case 2", $method, $name, $value, FALSE ); $this->{$method}( $name, $value ); return; } } // 3. fallback foreach( $map["fallback"] as $method ) { // show( "Case 3", $method, $name, $value, FALSE ); $this->{$method}( $name, $value ); return; } // 4. method getXyz() if( method_exists( $this, "set{$name}" ) ) { // show( "Case 4", "set{$name}", $value, FALSE ); $this->{"set{$name}"}( $value ); return; } // 5. property access if( property_exists( $this, $name ) ) { // show( "Case 5", $name, $value, FALSE ); $this->{$name} = $value; return; } throw new \BadMethodCallException("Unbekannte dynamische Eigenschaft: {$name}"); } }