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

发布于 2024-07-26 08:31:47 字数 672 浏览 7 评论 0原文

我一直担心通过字符串引用方法来调用方法。

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

$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);

I've always worry about calling methods by referencing them via strings.

Basically in my current scenario, I use static data mapper methods to create and return an array of data model objects (eg. SomeDataMapper::getAll(1234)). Models follow the Active Record design pattern. In some cases, there could be hundreds of records returned, and I don't want to put everything into memory all at once. So, I am using an Iterator to page through the records, as follows

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

while ($Iterator->hasNext()) {
  $data = $Iterator->next();
}

Is that a good way of doing this? Is it a bad idea to pass as strings the name of the mapper class and the method? I worry that this idea is not portable to other languages. Is this generally true for languages like Ruby and Python? If so, can anyone recommend a good alternative?

FYI, for future peoples' refernce, I call the method like this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

段念尘 2024-08-02 08:31:47

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

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

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

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

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

This is essentially a version of the factory pattern - Using strings to create a object instance.

However, I question the design idea of using an iterator to control the paging of data - that's not really the purpose of an iterator. Unless we just have name confusion, but I'd probably prefer to see something like this.

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

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

Of course, DataMapperPager::getResults() could return an iterator or whatever you'd want.

与他有关 2024-08-02 08:31:47

这是一种可以接受的做法。 Python 和 Ruby 都支持它,因此应该是可移植的。 Python 可以像 PHP 一样轻松地做到这一点,但 Ruby 的功能要多一些。 至少在Python中,当您引用的特定类尚未导入或在文件中尚未看到时(即该类在您尝试引用它的同一文件中的较低位置找到),它很有用。

从 Ruby 中的字符串获取类对象:http://infovore.org/archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing -that-c​​lasses-name/

It is an acceptable way of doing it. Both Python and Ruby support it and thus should be portable. Python can do it as easily as PHP can, however Ruby has a little more to it. In Python at least, it is useful for when the particular class you're referencing has not yet been imported nor seen yet in the file (i.e. the class is found lower in the same file as where you're trying to reference it.)

Getting a class object from a string in Ruby: http://infovore.org/archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing-that-classes-name/

左秋 2024-08-02 08:31:47

PHP 并不真正支持以任何其他方式传递函数。 PHP 中的所有动态方法调用函数都采用所谓的“回调” - 请参阅 http://us.php.net/manual/en/language.pseudo-types.php#language.types.callback 有关于此的文档。 正如您将看到的,它们只是不同使用模式下的字符串或字符串数​​组,因此您的情况并不遥远。

然而,有一些设计模式可以解决这个问题。 例如,您可以定义所有映射器类都必须实现的 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 doesn't really support the passing of functions any other way. All dynamic method invocation functions in PHP take what they call a "callback" - see http://us.php.net/manual/en/language.pseudo-types.php#language.types.callback for documentation on that. As you'll see, they're just string or arrays of strings in different usage patterns, so you're not far off.

There are however, design patterns that work around this. For instance, you could define a DataMapper interface that all of your mapper classes must implement. Then, instead of passing in the class and method as string, you could pass the mapper instance to your iterator and since it requires the interface it could call the interface methods directly.

pseudocode:

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)
  {
    ...
  }
 ...
}

Calling methods by name with passed in strings isn't horrible, there's probably only a performance penalty in that the bytecode generated can't be as optimized - there will always be a symbol lookup - but I doubt you'll notice this much.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文