如何在方法链中调用第一个带有“::”而其余部分为“->”的方法
how to call method with "::" in the first and "->" for the rest in method chaining
我想制作自己的 class 以用于与数据库交互,
如果我使用方法链,我认为它会很容易和可读。
但是我在静态调用第一个方法时遇到问题。
代码如下:
<?php
class Crud
{
protected static $action;
protected static $instance = null;
protected static $columns = [];
protected $data;
protected $db;
protected $query;
protected $table;
public function __construct()
{
$this->db = new mysqli('localhost', 'root', '', 'bahan_belajar');
if (!$this->db) {
echo "error";
}
return $this;
}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self;
}
return self::$instance;
}
public function select()
{
if (empty(func_get_args())) {
// $this->columns = "*";
self::$columns = "*";
} else {
if (is_array(func_get_args())) {
// self::columns = join(', ', func_get_args());
self::$columns = join(', ', func_get_args());
} else {
// self::columns = func_get_args();
self::$columns = func_get_args();
}
}
self::$action = "SELECT";
return $this;
}
public function from($tableName)
{
$this->table = ' FROM ' . $tableName;
return $this;
}
public function get($getName = 'object')
{
$this->query = self::$action . ' ' . self::$columns . ' ' . $this->table;
switch ($getName) {
case 'object':
$this->data = $this->db->query($this->query)->fetch_object();
break;
case 'array':
$this->data = $this->db->query($this->query)->fetch_array();
break;
case 'count':
$this->data = $this->db->query($this->query)->num_rows;
break;
}
return $this->data;
}
}
$chat = Crud::getInstance()->select('nama', 'teks')->from('chat')->get();
echo '<pre>';
print_r($chat);
echo '</pre>';
实际上,如果我首先使用 getInstance()
方法,这段代码可以正常工作,如上所示。但是,当我直接调用 select() 方法作为静态方法时,我该如何使它工作,例如:
$chat = Crud::select('nama', 'teks')->from('chat')->get();
如果我运行上面的代码我会得到一个错误,例如:
Fatal error: Uncaught Error: Using $this when not in object context in C:\xampp\htdocs\bahan_belajar\chat\classes.php:47 Stack trace: #0 C:\xampp\htdocs\bahan_belajar\chat\classes.php(74): Crud::select('nama', 'teks') #1 {main} thrown in C:\xampp\htdocs\bahan_belajar\chat\classes.php on line 47
我知道 select() 方法在可以用 ::
调用之前应该是一个静态方法(我认为),但是我怎样才能使它成为静态方法?
您只能将 ::
用于静态方法,将 ->
用于实例方法。这给您留下了 2 个选择:
选项 1:在链接之前显式获取实例
你需要用你的静态方法获取实例,然后使用->
链接,像这样:
Crud::getInstance()->select('nama', 'teks')->from('chat')->get();
选项 2:使用魔法方法
您的另一个选择是使用 magic methods. If you make your methods protected
or private
, you can intercept calls to those methods from outside the class with the __call()
and __callStatic()
magic methods. When you're in __callStatic()
,您可以通过调用 self::getInstance()
切换到使用实例。
这种方法可以让你做类似的事情
Crud::select('nama', 'teks')->from('chat')->get();
这里有一些非常简化的示例代码来演示这个想法 (demo on 3v4l):
class Test
{
public static $instance;
protected $myVar = 'foo';
// This intercepts instance calls ($testObj->whatever()) and handles them
public function __call($name, $args)
{
return call_user_func_array(array($this, $name), $args);
}
// This intercepts instance calls ($testObj->whatever()) and handles them
// The use of self::getInstance() lets us force static methods to act like instance methods
public static function __callStatic($name, $args)
{
return call_user_func_array(array(self::getInstance(), $name), $args);
}
public static function getInstance()
{
return self::$instance ? : new self;
}
protected function getMyVar()
{
echo $this->myVar;
}
protected function setMyVar($value)
{
$this->myVar = $value;
return $this;
}
}
echo Test::setMyVar(15)->getMyVar(); // successfully echoes 15
对所有这一切的重要说明:您所做的看起来很像重新发明 Eloquent, the ORM that ships with Laravel。从以前构建过自己的 ORM 的人那里获取:你最好使用像 Eloquent 这样的现有系统,它已经被编写并经过全面测试(并且可以在不需要你使用整个 Laravel框架)。构建 ORM 比看起来要难得多,而且,一旦开始,兔子洞就会越来越深。
我想制作自己的 class 以用于与数据库交互, 如果我使用方法链,我认为它会很容易和可读。 但是我在静态调用第一个方法时遇到问题。
代码如下:
<?php
class Crud
{
protected static $action;
protected static $instance = null;
protected static $columns = [];
protected $data;
protected $db;
protected $query;
protected $table;
public function __construct()
{
$this->db = new mysqli('localhost', 'root', '', 'bahan_belajar');
if (!$this->db) {
echo "error";
}
return $this;
}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self;
}
return self::$instance;
}
public function select()
{
if (empty(func_get_args())) {
// $this->columns = "*";
self::$columns = "*";
} else {
if (is_array(func_get_args())) {
// self::columns = join(', ', func_get_args());
self::$columns = join(', ', func_get_args());
} else {
// self::columns = func_get_args();
self::$columns = func_get_args();
}
}
self::$action = "SELECT";
return $this;
}
public function from($tableName)
{
$this->table = ' FROM ' . $tableName;
return $this;
}
public function get($getName = 'object')
{
$this->query = self::$action . ' ' . self::$columns . ' ' . $this->table;
switch ($getName) {
case 'object':
$this->data = $this->db->query($this->query)->fetch_object();
break;
case 'array':
$this->data = $this->db->query($this->query)->fetch_array();
break;
case 'count':
$this->data = $this->db->query($this->query)->num_rows;
break;
}
return $this->data;
}
}
$chat = Crud::getInstance()->select('nama', 'teks')->from('chat')->get();
echo '<pre>';
print_r($chat);
echo '</pre>';
实际上,如果我首先使用 getInstance()
方法,这段代码可以正常工作,如上所示。但是,当我直接调用 select() 方法作为静态方法时,我该如何使它工作,例如:
$chat = Crud::select('nama', 'teks')->from('chat')->get();
如果我运行上面的代码我会得到一个错误,例如:
Fatal error: Uncaught Error: Using $this when not in object context in C:\xampp\htdocs\bahan_belajar\chat\classes.php:47 Stack trace: #0 C:\xampp\htdocs\bahan_belajar\chat\classes.php(74): Crud::select('nama', 'teks') #1 {main} thrown in C:\xampp\htdocs\bahan_belajar\chat\classes.php on line 47
我知道 select() 方法在可以用 ::
调用之前应该是一个静态方法(我认为),但是我怎样才能使它成为静态方法?
您只能将 ::
用于静态方法,将 ->
用于实例方法。这给您留下了 2 个选择:
选项 1:在链接之前显式获取实例
你需要用你的静态方法获取实例,然后使用->
链接,像这样:
Crud::getInstance()->select('nama', 'teks')->from('chat')->get();
选项 2:使用魔法方法
您的另一个选择是使用 magic methods. If you make your methods protected
or private
, you can intercept calls to those methods from outside the class with the __call()
and __callStatic()
magic methods. When you're in __callStatic()
,您可以通过调用 self::getInstance()
切换到使用实例。
这种方法可以让你做类似的事情
Crud::select('nama', 'teks')->from('chat')->get();
这里有一些非常简化的示例代码来演示这个想法 (demo on 3v4l):
class Test
{
public static $instance;
protected $myVar = 'foo';
// This intercepts instance calls ($testObj->whatever()) and handles them
public function __call($name, $args)
{
return call_user_func_array(array($this, $name), $args);
}
// This intercepts instance calls ($testObj->whatever()) and handles them
// The use of self::getInstance() lets us force static methods to act like instance methods
public static function __callStatic($name, $args)
{
return call_user_func_array(array(self::getInstance(), $name), $args);
}
public static function getInstance()
{
return self::$instance ? : new self;
}
protected function getMyVar()
{
echo $this->myVar;
}
protected function setMyVar($value)
{
$this->myVar = $value;
return $this;
}
}
echo Test::setMyVar(15)->getMyVar(); // successfully echoes 15
对所有这一切的重要说明:您所做的看起来很像重新发明 Eloquent, the ORM that ships with Laravel。从以前构建过自己的 ORM 的人那里获取:你最好使用像 Eloquent 这样的现有系统,它已经被编写并经过全面测试(并且可以在不需要你使用整个 Laravel框架)。构建 ORM 比看起来要难得多,而且,一旦开始,兔子洞就会越来越深。