php - 将函数传递给类

标签 php class

的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 PatternsZend 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/

相关文章:

Java - Netbeans - 未找到主类

c - 你怎么称呼结构的实例?

php - OpenCart:下拉标题购物车信息的 div 在哪里?

PHP - 多数据库连接突然不工作

javascript - 如何进行实时搜索(包括加载搜索)

php - 获取PHP中的所有扩展类

java - 如何将 XML 文件中的值放入 java 中另一个类的数组列表中?

php - Symfony2 和提交机智 JavaScript : How to get html content

php - 如何创建 joomla 2.5 组件?

java - sun.reflect.CallerSensitive 注释是什么意思?