在PHP中通过字符串引用和调用方法是个坏主意吗?

在PHP中通过字符串引用和调用方法是个坏主意吗?,php,iterator,data-mapping,Php,Iterator,Data Mapping,我总是担心通过字符串引用方法来调用方法 基本上在我当前的场景中,我使用静态数据映射器方法创建并返回数据模型对象数组(例如SomeDataMapper::getAll(1234))。模型遵循活动记录设计模式。在某些情况下,可能会返回数百条记录,我不想一下子把所有内容都放到内存中。因此,我使用迭代器对记录进行分页,如下所示 $Iterator = new DataMapperIterator('SomeDataMapper', 'getAll', array(1234)); while ($Ite

我总是担心通过字符串引用方法来调用方法

基本上在我当前的场景中,我使用静态数据映射器方法创建并返回数据模型对象数组(例如SomeDataMapper::getAll(1234))。模型遵循活动记录设计模式。在某些情况下,可能会返回数百条记录,我不想一下子把所有内容都放到内存中。因此,我使用迭代器对记录进行分页,如下所示

$Iterator = new DataMapperIterator('SomeDataMapper', 'getAll', array(1234));

while ($Iterator->hasNext()) {
  $data = $Iterator->next();
}
这样做好吗?将映射器类和方法的名称作为字符串传递是不是一个坏主意?我担心这个想法无法移植到其他语言。对于Ruby和Python这样的语言,这通常是正确的吗?如果是这样,有人能推荐一个好的替代方案吗

供大家参考,我将这种方法称为:

$method = new ReflectionMethod($className, $methodName);
$returnValue = $method->invokeArgs(null, $parameters);

这是一种可以接受的做法。Python和Ruby都支持它,因此应该是可移植的。Python可以像PHP一样轻松地完成这项工作,不过Ruby还有一点需要改进。至少在Python中,当您引用的特定类尚未导入或尚未在文件中看到时(即,该类位于您试图引用它的同一文件的较低位置),它非常有用


从Ruby中的字符串获取类对象:

这是一种可以接受的方法。Python和Ruby都支持它,因此应该是可移植的。Python可以像PHP一样轻松地完成这项工作,不过Ruby还有一点需要改进。至少在Python中,当您引用的特定类尚未导入或尚未在文件中看到时(即,该类位于您试图引用它的同一文件的较低位置),它非常有用


从Ruby中的字符串获取类对象:

PHP实际上不支持以任何其他方式传递函数。PHP中的所有动态方法调用函数都采用它们称之为“回调”的方法—有关该方法的文档,请参阅。正如您将看到的,它们只是不同使用模式下的字符串或字符串数组,所以您已经不远了

然而,有一些设计模式可以解决这个问题。例如,可以定义所有映射器类都必须实现的DataMapper接口。然后,您可以将映射器实例传递给迭代器,而不是将类和方法作为字符串传递,因为它需要接口,所以可以直接调用接口方法

伪代码:

interface DataMapper
{
   public function mapData($data);
}

class DataMapperIterator ...
{
  public function __construct(DataMapper $mapper, ...)
  {
   ...
  }
  ...
  public function next()
  {
    ... now we can call the method explicitly because of interface ...
    $this->mapper->mapData($data);
  }
}

class DataMapperImplemenation implements DataMapper
{
  ...
  public function mapData($data)
  {
    ...
  }
 ...
}

使用传入字符串按名称调用方法并不可怕,可能只会对性能造成影响,因为生成的字节码无法进行优化—始终会有符号查找—但我怀疑您是否会注意到这一点。

PHP并不真正支持以任何其他方式传递函数。PHP中的所有动态方法调用函数都采用它们称之为“回调”的方法—有关该方法的文档,请参阅。正如您将看到的,它们只是不同使用模式下的字符串或字符串数组,所以您已经不远了

然而,有一些设计模式可以解决这个问题。例如,可以定义所有映射器类都必须实现的DataMapper接口。然后,您可以将映射器实例传递给迭代器,而不是将类和方法作为字符串传递,因为它需要接口,所以可以直接调用接口方法

伪代码:

interface DataMapper
{
   public function mapData($data);
}

class DataMapperIterator ...
{
  public function __construct(DataMapper $mapper, ...)
  {
   ...
  }
  ...
  public function next()
  {
    ... now we can call the method explicitly because of interface ...
    $this->mapper->mapData($data);
  }
}

class DataMapperImplemenation implements DataMapper
{
  ...
  public function mapData($data)
  {
    ...
  }
 ...
}

使用传入字符串按名称调用方法并不可怕,可能只会对性能造成影响,因为生成的字节码无法进行优化—始终会有符号查找—但我怀疑您是否会注意到这一点。

这本质上是工厂模式的一个版本—使用字符串创建对象实例

然而,我质疑使用迭代器控制数据分页的设计思想——迭代器的目的并不是这样。除非我们只是名称混淆,但我可能更愿意看到这样的东西

$pager = new DataMapperPager( 'SomeDataMapper', 'someMethod', array(1234) );
$pager->setPageNum( 1 );
$pager->setPageSize( 10 );
$rows = $pager->getResults();

foreach ( $rows as $row )
{
   // whatever
}

当然,DataMapperPager::getResults()可以返回迭代器或您想要的任何东西。

这本质上是工厂模式的一个版本-使用字符串创建对象实例

然而,我质疑使用迭代器控制数据分页的设计思想——迭代器的目的并不是这样。除非我们只是名称混淆,但我可能更愿意看到这样的东西

$pager = new DataMapperPager( 'SomeDataMapper', 'someMethod', array(1234) );
$pager->setPageNum( 1 );
$pager->setPageSize( 10 );
$rows = $pager->getResults();

foreach ( $rows as $row )
{
   // whatever
}

当然,DataMapperPager::getResults()可以返回迭代器或您想要的任何东西。

好的方面,我也想这样做,但我的映射器的方法是静态的。另外,对于不同类型的结果集,我有不同的映射器方法……比如::getById()、getByGroupId()等等。好的方面,我想这样做,但是我的映射器的方法是静态的。另外,对于不同类型的结果集,我有不同的映射器方法……比如::getById()、getByGroupId()等等。很好。我想我会把它重命名为*Pager,然后让它按照你的建议返回一个迭代器。实际上,我最终实现了PHP的迭代器接口,这样我就可以在foreach中使用这个类了。很好。我想我会把它重命名为*Pager,然后让它按照你的建议返回一个迭代器。实际上,我最终实现了PHP的迭代器接口,这样我就可以在foreach中使用这个类。