monolyth/mural

此包已被弃用,不再维护。未建议替代包。

MUltiple "Resource" AutoLoader

0.3.0 2016-07-16 08:38 UTC

This package is auto-updated.

Last update: 2022-10-07 16:47:14 UTC


README

MUltiple "Resource" AutoLoader

Mural 是一个小型包,包含一个自定义的自动加载器,可以从同一仓库中理智地提供和测试多个 "app"(通常是网站),同时保持共享代码库的整洁。

安装

Composer(推荐)

composer require monolyth/mural

手动

克隆或下载仓库,并确保 Monolyth\\Mural 命名空间映射到 Mural 的 src 目录。由于它只有一个文件,您也可以手动 require 它。

问题

您的普通小型网站将在某个地方(例如,src)有代码,并有一个公共目录,其中包含您的 index.php 前端控制器(例如,httpdocs)。由于通常 httpdocs 只包含静态文件,您可以将自动加载器(例如,在 composer.json 中)设置为查看 src 并完成它。同样适用于任何外部包。

然而,更复杂的项目将具有多个面向公共的路径,一些项目特定的覆盖,但主要是大量共享的代码。

可以通过调整 PHP 的 include_path 来自动包含正确的代码,但这在测试期间有问题:您需要一个针对每个项目(网站)的测试套件,因为类名将是相同的,并触发致命错误。

解决方案

Mural 自动加载器允许您特别命名这些覆盖,同时仍然将 "原始" 命名空间暴露给消费类。在测试期间,只需不包含它,并用原始的、完全命名空间(因此是唯一的)类进行测试即可。在您的应用程序中使用 "标准化" 的类名。

WHY $DEITY??? 一个例子

好吧,更多的澄清。这实际上是一个真实世界的例子。

假设你有一组约会网站。有很多功能(消息、资料编辑等)是共享的,但也有一些特定的功能。 straight.com 面向异性恋者,而 gay.com 面向同性恋者(duh)。除了标志和一些其他的 CSS,它们是相同的,但在一个重要的方面不同:在搜索时,straight.com 应仅匹配男性和女性的结果,而 gay.com 应仅匹配男性和男性或女性和女性的结果。一个虚构的目录结构可能如下所示

/path/to/sites
    /vendor <- packages
    /src <- shared source code
    /straight.com
        /Search.php
    /gay.com
        /Search.php

通常,这两个 Search 类将简单地称为 \Search,或者它们会在它们网站的命名空间中(例如,Straight\Search 等),您将不得不记住在您的(共享)控制器中加载正确的类,这是很繁琐的

<?php

class SearchController
{
    public function search()
    {
        if ($_SERVER['SERVER_NAME'] == 'straight.com') {
            $search = new Straight\Search;
        } else {
            $search = new Gay\Search;
        }
        // ...
    }
}

你明白我的意思了。这种代码让我感到不舒服,而且它很快就变得难以维护。我想要做的是这个

<?php

class SearchController
{
    public function search()
    {
        $search = new Search;
        // ...
    }
}

...并在其他地方处理 Search 组件的覆盖。那时,Mural 就诞生了!

它是如何工作的

Mural 将自己添加到自动加载器堆栈中,并重新编写它指定的类名

<?php

$mural = new Monolyth\Mural\Autoloader;
$mural->rewrite('\\', 'Straight\\');

上述示例本质上表示“对于每个类,首先检查是否存在在Straight\\下的版本。如果存在,则使用该版本”。

关于PHP有很多可以说的,但其自动加载机制设计得相当周到。如果没有“别名”类,Mural将直接将自动加载逻辑传递给链中的下一个自动加载器。

总结

straight.com/index.php

<?php

$mural = new Monolyth\Mural\Autoloader;
$mural->rewrite('\\', 'Straight\\`);

...以及在gay.com/index.php

<?php

$mural = new Monolyth\Mural\Autoloader;
$mural->rewrite('\\', 'Gay\\');

...最后,在测试中,只需测试Straight\SearchGay\Search

Mural会盲目地检查字符串匹配,并在strpos === 0时启动操作。因此,您也可以仅覆盖子命名空间,传递完整的类名等。

常见问题解答和注意事项

关于类型检查的注意事项

class_alias重命名您的类,但保留其他“元数据”完整。因此,使用上述示例

<?php

$search = new Search;
echo get_class($search); // Straight\Search
echo $search instanceof Straight\Search; // true
echo $search instanceof Search; // also true!

类、特质、接口...

Mural支持所有这些。

递归性

对于全局重写(即,如上述示例中的空命名空间)Mural不会“递归”,即

<?php

$mural->rewrite('\\', 'Foo\\');

// Bar gets rewritten to Foo\Bar, but Bar\Baz is autoloaded verbatim.
class Bar extends Bar\Baz
{
}

// To rewrite Bar\Baz to Foo\Bar\Baz as well, you'd need an extra call to
// `rewrite` as follows:

$mural->rewrite('Bar', 'Foo\\Bar\\');

简单的原因是对于全局命名空间,这会导致无限循环(以及段错误)。

前导和尾随反斜杠

前导反斜杠会自动删除,是可选的。尾随反斜杠很重要

1. Alias with a trailing backslash to specify a namespace;
2. Alias without the backslash to alias a _classname_.