I am trying to build a database-class that allows method chaining to query it. I want to instantiate it like Laravel's Eloquent by making the first call static.
See this example:
class Database
{
public function construct($data) {
$this->data = $data;
}
public function filter($criteria) {
// ...
return $this;
}
public static function filter($data, $criteria) {
$obj = new Database($data);
$obj->filter($criteria);
return $obj;
}
public function add($value) {
// ...
return $this;
}
public static function add($data, $value,) {
$obj = new Database($data);
$obj->add($value);
return $obj;
}
}
This would allow me for example:
Database::add($myData, $newValue)->add($anotherValue)->filter('isString');
Database::filter($myData, 'isNumber')->add($thirdValue);
This is not supposed to be the real thing, but I am curious if there was a way to reduce the duplicated code throughout my static methods or to remove them entirely.
I thought of the magic method __callStatic()
but I am not sure if it is the best way to achieve it.
I would appreciate it if someone who knows could explain me, how big frameworks deal with this kind of task.
CodePudding user response:
Yea it is indeed done through magic method __callStatic()
.
Here you have Laravel Eloquent code snippets, these are taken from Model class, there is more things going on, but these are relevant to your case:
public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters); // delegating to __call method
}
public function __call($method, $parameters)
{
...
// self explanatory
return $this->forwardCallTo($this->newQuery(), $method, $parameters);
}
// newQuery method lead to this method:
public function newModelQuery()
{
return $this->newEloquentBuilder(
$this->newBaseQueryBuilder() // deals with getting database connection
)->setModel($this);
}
// newEloquentBuilder return Builder class which have the "where" etc. methods defined.
In your case simple example:
class Database
{
protected static $connection;
protected $query; // could be array or better object
public function __construct() {
if(!static::$connection){
static::$connection = new mysqli(...); // for example
}
}
public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters);
}
// in case $query is object have these two methods defined there
// also delegate with __call method to the query object
public function filter($criteria) {
... // filling $query variable
return $this;
}
public function add($value) {
... // filling $query variable
return $this;
}
public function fetch_assoc() {
$stmt = static::$connection->prepare(...);
... // fill the prepared statements with $query data
return $stmt->get_result()->fetch_assoc();
}
}
CodePudding user response:
You can use static methods from object, but you cannot use $this in that method.
You cannot define static and not static methods with the same name.
In most cases I need only the not static method, and in rare case I don't have an object instance I instantiate just for this method call - and call the non-static method.
In rare cases I define the static method too with different name, for example filterStatic(). This is a very rare case, and in this case the non-static method wraps the static one to avoid code duplication.