在PHP中如何调用链式方法

3

我称返回某些链接方法的数组的对象为:

Songs::duration('>', 2)->artist('Unknown')->genre('Metal')->stars(5)->getAllAsArray();

问题在于每次我想要获取这个数组,例如在另一个脚本中,我必须再次链接一切。现在想象一下,在超过10个脚本中都需要这样做。

有没有一种方法可以在以后调用链接的方法?


无法缓存结果。假设查询会随着人们评价歌曲而改变。 - DarkGhostHunter
你可以创建一个函数或类/方法来包装这个链。如果你创建一个简单的接受数组的方法,你就可以跳过中间步骤。 - Rasclatt
@Rasclatt 听起来不错,我会尝试进行一些测试,看看如何推进。 - DarkGhostHunter
虽然这个方法不太被推荐使用,但是你可以使用__callStatic()(如果你的PHP允许这种重载方法)来部分地通过函数名和参数来执行操作。比如\Songs::unknown_metal(5);,当然假设'>', 2是相同的...否则它们也必须作为参数传递进去。 - Rasclatt
3个回答

0

如果您无法按照建议进行缓存,正如我所评论的那样,这里有几个想法。如果您的应用程序允许混合使用函数(例如,符合公司开发规则的标准),您可以使用函数包装器:

// The function can be as complex as you want
// You can make '>', 2 args too if they are going to be different all the time
function getArtists($array)
    {
        return \Songs::duration('>', 2)->artist($array[0])->genre($array[1])->stars($array[2])->getAllAsArray();
    }

print_r(getArtists(array('Unkown','Metal',5)));

如果您只允许使用类,并且在您的开发中未禁用__callStatic(),并且该函数在您使用的PHP版本中可用,则可以尝试使用它:

// If you have access to the Songs class
public __callStatic($name,$args=false)
    {
        // This should explode your method name
        // so you have two important elements of your chain
        // Unknown_Metal() should produce "Unknown" and "Metal" as key 0 and 1
        $settings = explode("_",$name);
        // Args should be in an array, so if you have 1 value, should be in key 0
        $stars = (isset($args[0]))? $args[0] : 5;
        // return the contents
        return self::duration('>', 2)->artist($settings[0])->genre($settings[1])->stars($stars)->getAllAsArray();
    }

这应该返回与您的链相同的内容:

print_r(\Songs::Unknown_Metal(5));

需要注意的是,重载很难跟踪,因为没有具体的方法叫做Unknown_Metal,所以调试更加困难。此外,请注意我尚未在本地测试过这个特定的设置,但我已经注明了应该发生的情况。

如果不允许这些,那么我会创建一个缩短该链的方法:

public function getArtists($array)
    {
        // Note, '>', 2 can be args too, I just didn't add them
        return self::duration('>', 2)->artist($array[0])->genre($array[1])->stars($array[2])->getAllAsArray();
    }

print_r(\Songs::getArtists(array('Unkown','Metal',5)));

0

由于您无法缓存结果,因此可以在数组中缓存调用链的结构。

$chain = [
    'duration' => ['>', 2],
    'artist' => 'Unknown',
    'genre' => 'Metal', 
    'stars' => 5,
    'getAllAsArray' => null
];

你可以使用一个函数来模拟使用缓存数组的链式调用:

function callChain($object, $chain) {
    foreach ($chain as $method => $params) {
        $params = is_array($params) ? $params : (array) $params;
        $object = call_user_func_array([$object, $method], $params);
    }
    return $object;
}

$result = callChain('Songs', $chain);

0

我写了一个库,完全实现了你所寻找的功能,并以高质量的方式实现了Don't Panic建议的原则:https://packagist.org/packages/jclaveau/php-deferred-callchain

在你的情况下,你需要编写以下代码:

$search = DeferredCallChain::new_(Songs::class)  // or shorter: later(Songs::class)
    ->duration('>',2)   // static syntax "::" cannot handle chaining sadly
    ->artist('Unknown')
    ->genre('Metal')
    ->stars(5)
    ->getAllAsArray();

print_r( $search($myFirstDBSongs) );
print_r( $search($mySecondDBSongs) );

希望它能够满足您的需求!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接