I’ve got a Queryable trait which implements the __callStatic method to make a new instance of a Builder and run the called function on it (if it exists). It returns the Builder in order to chain queries (much like Eloquent).
Now I’m trying to implement an interface that needs the find() function but I’ve got the find() function declared in phpDoc on the Quaryable trait (@method static static find(mixed $primaryKeyValue)
) and it creates a conflict:
Declaration of ‘Queryable::find(primaryKeyValue: mixed)’ must be compatible with ‘StorageInterface->find(primaryKeyValue: mixed)’, cannot make interface method
In order to fix the conflict, I’m trying to use something like the trait alias (use Queryable { Queryable::find as queryFind; }
) to resolve it, but then I get hit with the
Compile Error: An alias was defined for appFrameworkTraitsQueryable::find but this method does not exist
I can’t seem to find a solution for this, could some guru help me out? 🙂 (pretty sure it has to do with somekind of exists check on the class that fails because it is a magic method but I wouldn’t know how to fix that either..)
<?php
namespace appFrameworkTraits;
use appFrameworkDatabaseBuilder;
use appFrameworkDatabasePaginator;
/**
* @method static int count()
* @method static static|array<static> first(int $amount = 1)
* @method static static|array<static> last(int $amount = 1)
* @method static string getQuery()
* @method static string getRawQuery()
* @method static string getPrimaryKey()
* @method static static find(mixed $primaryKeyValue)
* @method static array<static> all()
* @method static array<static> get()
* @method static Paginator paginate()
* @method static Builder table(string $tableName)
* @method static Builder primaryKey(string $primaryKey)
* @method static Builder perPage(int $perPageAmount)
* @method static Builder where(string $column, mixed $operatorOrValue = null, mixed $value = null)
* @method static Builder whereIn(string $column, array $search)
* @method static Builder whereNotNull(string $column)
* @method static Builder select(...$columns)
* @method static Builder with(string $relation, Closure $closure)
* @method static Builder orderBy(string $column, string $direction = 'desc')
* @method static Builder limit(int $amount)
* @method static Builder offset(int $amount)
*/
trait Queryable
{
public static function __callStatic(string $name, array $arguments)
{
$functions = get_class_methods(Builder::class);
if (in_array($name, $functions)) {
$builder = new Builder(static::class);
return $builder->$name(...$arguments);
}
$selfFunctions = get_class_methods($calledClass = static::class);
if (!in_array($name, $selfFunctions)) {
throw new BadMethodCallException("Static method '{$name}' does not exist on {$calledClass}.");
}
return static::$name(...$arguments);
}
}
class BaseModel extends stdClass implements QueryableInterface, StorableInterface
{
use Queryable {
Queryable::find as queryFind;
}
public function find(mixed $primaryKeyValue): static
{
return self::queryFind($primaryKeyValue);
}
}
<?php
namespace appStorageMethods;
interface StorableInterface
{
function getObject(mixed $primaryKeyValue): static;
function find(mixed $primaryKeyValue): static;
function save(): static;
}
2
Answers
Trait methods can be "renamed": (actually it’s an alias)
Reference
Simple example:
Well, you want even more magic. The following code is absolutely not recommended due to
debug_backtrace
usage which i believe should not be met in the production code when everything goes as it should: