的PHP
mysql数据库
我在这里创建了对此问题的追随者,即specifically about pagination
我需要从另一个类的一个类中调用一个方法,并且能够更改所调用的方法。像这样
class db{
function a(){ echo 'I run a query';}
function b(){ echo 'im the other query';}
}
class YourClass {
var $fcn;
$db = new db()
function invoke(){
call_user_func($this->fcn);
}
}
$instance = new YourClass;
$instance->fcn = 'db->a';
$instance->invoke();
我想在'yourClass'方法'invoke'中使用db类中的方法'a'
谢谢
好的,这是我从提供的答案中得出的结论,它可以正常工作。
class A {
function a(){
$x = 'Method a is used';
return $x;
}
function b(){
$x = 'Method b is used';
return $x;
}
}
class B {
function invoke($obj, $method){
echo call_user_func( array( $obj, $method) );
}
}
$instance = new B();
$instance->invoke(new A(),"a");
在屏幕上写“使用方法a”
但是我真的很希望能够将参数传递给方法“ a”,所以我尝试了下面的代码。
class A {
function a($var1,$var2,$var3){
$x = 'the three passed values are ' . $var1 . ' and ' . $var2 . ' and ' . $var3;
return $x;
}
function b(){
$x = 'im method b';
return $x;
}
}
class B {
function invoke($obj,$arguments){
echo call_user_func_array($obj,$arguments);
}
}
$arguments = array('apple','banana','pineapple');
$use_function = array(new A(),"a");
$instance = new B();
$instance->invoke($use_function,$arguments);
它几乎可以正常工作,但我在正确答案之上得到了这些错误
同样缺少参数2和3的A :: a(),.....的参数1,但是答案会打印到屏幕上
“传递的三个值是苹果,香蕉和菠萝”
我可能整天都在写菜鸟错误。如果有人可以修复上面的脚本并提交工作代码,我将不胜感激。我必须把这个问题上床睡觉,这样我才能上床睡觉。
谢谢
最佳答案
从PHP5.3开始,您可以使用闭包或函子来传递方法。在此之前,您可以使用create_function()编写匿名函数,但这很尴尬。
基本上,您要尝试执行的操作可以通过Strategy Pattern完成。
删除了示例代码,因为在OP更改问题后不再有用(请参阅Wiki)
除此之外,您可能还需要研究Fowlers的Data Source Architectural Patterns。 Zend Framework(以及几乎所有其他PHP框架)提供了可用于这些模式的database access classes,并且还有一个paginator class,所以为什么不检查它们以了解它们是如何做到的。
删除了EDIT 1,因为OP更改了问题后它不再有帮助(请参阅Wiki)
编辑2
好的,让我们逐步解决此问题(尽管不使用策略模式)
您可以使用以下代码轻松解决问题中的要求:
class Foo
{
public function bar()
{
echo 'bar method in Foo';
}
}
class MyInvoker
{
protected $myObject;
public function __construct()
{
$this->myObject = new Foo();
}
public function __call($method, $args)
{
$invocation = array($this->myObject, $method);
return call_user_func_array($invocation, $args);
}
}
使用此代码,您只需调用适当的方法。没有设置方法名称。没有笨拙的额外调用方法。没有重新发明方法的调用方式。您不需要它,因为PHP刚刚教过__call函数将MyInvoker中不存在的所有方法发送到$ myObject,例如Foo:
$invoker = new MyInvoker;
$invoker->bar(); // outputs 'bar method in Foo called'
您可能也已经将MyInvoker扩展为Foo的子类,例如
class MyInvoker extends Foo {}
然后您可以执行相同操作。但是,这不是您所需要的,它说明了做这样的事情是没有意义的。 MyInvoker现在不执行任何操作。它是一个空类,实际上与Foo相同。即使使用__call方法的先前方法也没有执行任何操作。这就是为什么我要您更详细地说明期望的结果,即分页器。
第一次尝试:
class Paginator()
{
// A class holding all possible queries of our application
protected $queries;
// A class providing access to the database, like PDO_MySql
protected $dbConn;
public function __construct()
{
$this->db = new MyPdo();
$this->queries = new DbQueries();
}
public function __call($method, $args)
{
$invocation = array($this->queries, $method);
$query = call_user_func_array($invocation, $args);
return $this->dbConn->query($query);
}
}
使用该代码,我们的Paginator在其内部创建所需的所有内容,将db连接类和所有查询紧密耦合,并允许您调用这些,就像这样
$paginator = new Paginator;
// assuming we have something like getImageCount() in DbQueries
echo $paginator->getImageCount();
然后发生的是,Paginator将识别出它不知道getImageCount()并将调用__call方法。 __call方法将尝试在DbQueries上调用getImageCount()方法。既然存在,它将返回查询,该查询又传递给db连接以执行查询。你会说很棒,但事实并非如此。实际上,这太可怕了。分页器的责任是对表中的项目进行计数,并从该表中获取一定范围和数量的项目。但是现在,它没有做任何这样的事情。它完全不知道发生了什么,所以让我们尝试一个新的类:
class Paginator
{
protected $dbConn;
protected $itemCount;
public function __construct($dbConn)
{
$this->dbConn = $dbConn;
}
public function countItems($query)
{
$this->itemCount = $this->dbConn->query('select count(*) from (?)', $query);
return $this->itemCount;
}
public function fetchItems($query, $offset = 0, $limit = 20)
{
$sql = sprintf('select * from (?) LIMIT %d, %d', $offset, $limit);
return $this->dbConn->query($sql, $query);
}
}
好多了。现在,我们的Paginator是一个聚合而不是一个复合,这意味着它不会实例化其内部的对象,而是要求它们在构造函数中传递给它。这称为dependency injection(并且当dbConn使用loose coupling时,还提供了interface),这将使您的应用程序更易于维护,因为现在可以轻松交换组件。当Unit Testing您的代码时,这也将派上用场。
另外,您的分页器现在专注于应做的事情:计数和获取任意查询的项目。无需传递方法。无需晦涩的方法调用。您可以这样使用它:
$paginator = new Paginator($dbConn);
$query = $dbQueries->findImagesUploadedLastWeek(); // returns SQL query string
$images = $paginator->countItems($query);
if($images > 0) {
$images = $paginator->fetchItems($query);
}
就是这样。好吧,差不多。您当然必须呈现分页。但是,如果您扩展上面已有的内容,这应该是微不足道的。 $ imageCount属性是下一步的提示。
无论如何,希望我能有所启发。
附言
$this->dbConn->query($sql, $query)
调用当然是伪代码。不要期望能够复制和粘贴它并使它正常工作。此外,您应确保添加到Paginator SQL的查询可以安全使用。您不希望有人插入删除所有数据库行的查询。永远不要相信用户输入。P.P.S.
$query
应该是一个SQL查询字符串。检查PHP手册中的PDO::prepare。通常,在执行语句之前准备语句会产生更好的性能和安全性。手册中的页面将为您提供有关查询调用中?
的线索。如果您不想使用PDO,只需使用sprintf()
或str_replace()
将?
替换为$query
,例如$this->dbConn->query(sprintf('SELECT count(*) from (%s)', $query)
,但请记住,这没有准备语句的好处,并且可能为SQL Injection漏洞打开大门。P.P.P.S是,Dependency Injection通常是首选策略。尽管这是一个高级主题,但现在可能无法完全掌握,但是值得研究。就目前而言,如果您倾向于偏爱聚合而不是合成,那么就足够了。您的类仅应执行其职责,并通过构造函数获取任何依赖关系。
关于php - 将函数传递给类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1733582/