基于静态类的PHP软件设计模式

时间:2014-03-18 11:20:21

标签: php oop design-patterns software-design

我注意到一些最近流行的PHP库中的常见模式,例如Laravel,其中API主要基于静态类和方法。这种API的典型示例:

Logger::note('Handle routes for the welcome area of the site.');
Route::match('/welcome/:id', function ($id) {
    $name = Model::from('users')->get('name')->where('id', $id);
    $body = Template::body('templates/wecome.tpl', array('name' => $name));
    HTTP::respond(200, $body);
}

代码看起来非常易读,并且5个不同的静态类由Composer自动加载,所以乍一看这似乎是一个有吸引力的模式。我的问题是,对于那些在设计API方面经验丰富的人来说,随着事情的扩大,这似乎是一种很好的方法吗?

举一个例子,我可以立即看到地平线上的一些笨拙,例如我应该要保留多个日志。在非静态模式中,我可以这样做:

$debugLog = new Logger('logs/debug.log');
$errorLog = new Logger('logs/errors.log');
Route::match('/welcome/:id', function ($id) {
    $debugLog->note('Handle routes for the welcome area of the site.');
    $name = Model::from('users')->get('name')->where('id', $id);
    if (empty($name)) {
        $errorLog->warn('Name is empty!');
    }
}

但是很难分享许多不同的方法和文件。

#file1.php
Route::match('/welcome/:id', function ($id) {
    $debugLog = new Logger('logs/debug.log');
    $debugLog->note('Handle routes for the welcome area of the site.');
    //etc
}
#file2.php
Route::match('/news', function ($id) {
    $debugLog = new Logger('logs/debug.log');
    $debugLog->note('Handle routes for the news area of the site.');
    if ($error) {
        $errorLog = new Logger('logs/errors.log');
        $errorLog->warn('There is some problem: '.$error);
    }
}

现在我不得不重复自己,以便在整个地方实例化非静态类,这至少会使代码变得混乱,并且可能会使维护变得更难。

但是,另一方面,看起来每个类的静态方法也不容易扩展。假设我想使用静态API拥有多个日志;我可以尝试一些单身人士和工厂......

Logger::get('debug')->note('Handle routes for the welcome area of the site.');
Logger::get('errors')->note('Danger!');

但这似乎只是将API从方法名称转换为字符串参数(可能拼写错误等)。如果我想要两个不同的“调试”记录器怎么办?

无论是哪种方式,我倾向于静态,基于另一方,或基于另一方的实例,似乎随着模式的使用增长,我遇到了限制。

关于最佳方法的任何建议,因为我不想用重复的实例化代码填充我的应用程序,但我还希望灵活性能够根据现有的类增加更多种类?

1 个答案:

答案 0 :(得分:0)

Laravel中的这些静态类实际上是美化的服务定位器。 "句法糖"他们称之为" Facade" (这不是一个好名字,但泰勒称之为,不要将其与http://en.wikipedia.org/wiki/Facade_pattern混淆)

Route::get('/', 'HomeController@showWelcome');

可以写成

$app['router']->get('/', 'HomeController@showWelcome');

了解详情:http://taylorotwell.com/response-dont-use-facades/