加载同一类的多个版本 [英] Loading multiple versions of the same class

查看:79
本文介绍了加载同一类的多个版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

比方说,我发布了一个代码库作为独立的PHP类.然后,有人在其应用程序中使用该库的1.0版.后来,我发布了该库的2.0版,无论出于何种原因,同一个人都需要在其应用程序中同时使用1.0和2.0,因为他或我都破坏了与新版本的向后兼容性.

Let's say I release a code library as a standalone PHP class. Someone then uses version 1.0 of that library in their application. Later, I release version 2.0 of the library and that same someone, for any reason, needs to use both 1.0 and 2.0 side-by-side in their application because either he or I broke backwards compatibility with the new release.

如果类名不同,则很容易包含和实例化这两个类,因为没有命名冲突.但是,如果类名保持不变,则会遇到问题:

If the class names are different, it's easy enough to include and instantiate both because there's no naming conflict. But if the class names are kept the same, we run into problems:

include /lib/api-1.0/library.php;
$oldlibary = new Library();

include /lib/api-2.0/library.php;
$newlibrary = new Library();

这是行不通的,因为我们不能同时加载两个名称均为Library的类.另一个开发人员建议的替代方法是使用名称空间.以下应该可以工作:

This just won't work because we can't load two classes both with the name Library. One alternative another developer suggested was to use namespaces. The following should work:

namespace old {
    include /lib/api-1.0/library.php;
}
namespace new {
    include /lib/api-2.0/library.php;
}

$oldlibary = new old\Library();
$newlibrary = new new\Library();

不幸的是,这不是很可扩展.它可以在2实例的情况下工作(希望我不必先使用),但是要将其缩放到3、4、5或更多实例,则需要定义其他名称空间并进行设置,如果您不首先使用这些名称空间,那将是一堆不必要的代码.

Unfortunately, this isn't very scalable. It would work with a 2-instance situation (which, hopefully, I wouldn't have to use in the first place), but to scale it to 3, 4, 5, or more instances you'd need to have additional namespaces defined and set up, If you're not using those namespaces in the first place, that's a bunch of unnecessary code.

那么,有没有一种方法可以动态创建名称空间,包含文件并实例化包含在该文件中的类的唯一命名的变量?

So is there a way to dynamically create a namespace, include a file, and instantiate the class contained within that file in a uniquely-named variable?

让我添加更多说明...

Let me add some more clarification ...

我正在构建一组库,供其他开发人员使用,这些开发人员为几个CMS平台构建插件/模块.理想情况下,每个人都将始终使用我库的最新版本,但是我不能保证,也不能保证最终用户将在新版本可用时始终升级其模块.

I'm building a set of libraries to be used by other developers who build plugins/modules for a couple of CMS platforms. Ideally, everyone would always use the latest version of my library, but I can't guarantee that and I can't guarantee the end user will always upgrade their modules when new versions become available.

我要使用的用例是最终用户由两个不同的开发人员安装两个不同的模块:称它们为 Apple Orange .这两个模块都使用我的库的1.0版,这很棒.我们可以一次实例化它,两组代码都可以从该功能中受益.

The use case I'm trying to work with is one where the end user installs two different modules by two different developers: call them Apple and Orange. Both modules are using version 1.0 of my library, which is great. We can instantiate it once and both sets of code can benefit from the functionality.

稍后,我向该库发布了一个次要补丁.它的版本为1.1,因为它不破坏与1.x分支的向后兼容性. Apple 的开发人员立即更新其本地版本,并推送其系统的新版本. Orange 的开发人员正在休假,不会打扰.

Later, I release a minor patch to this library. It's versioned 1.1 because it doesn't break backwards compatibility with the 1.x branch. The developer of Apple immediately updates his local version and pushes a new edition of his system. The developer of Orange is on vacation and doesn't bother.

当最终用户更新 Apple 时,她获得了我库的最新维护版本.因为它是维护版本,所以可以完全替换1.0版是安全的.因此,即使开发人员从不费心去更新其发行版,代码也只能实例化1.1和 Orange 的维护补丁.

When the end user updates Apple she gets the latest maintenance release of my library. Because it's a maintenance release, it's assumed to be safe to completely replace version 1.0. So the code only instantiates 1.1 and Orange benefits from a maintenance patch even though the developer never bothered to update their release.

甚至后来,出于某种原因,我决定更新我的API以向Facebook添加一些挂钩.新功能和API扩展对该库进行了很多更改,因此我将版本升级到2.0,以将其标记为在所有情况下都可能不向后兼容. Apple 再一次进入并更新他的代码.没有任何问题,他只是用最新版本替换了/lib文件夹中的我的库. 橙色决定重返学校当小丑,但已停止维护他的模块,因此它没有任何更新.

Even later, I decide to update my API to add some hooks to Facebook for some reason. The new features and API extensions change a lot about the library, so I up the version to 2.0 to flag it as potentially not backwards-compatible in all situations. Once again, Apple goes in and updates his code. Nothing broke, he just replaced my library in his /lib folder with the latest version. Orange decided to go back to school to become a clown and has stopped maintaining his module, though, so it doesn't get any updates.

当最终用户使用新版本更新 Apple 时,她会自动获取我的图书馆的2.0版.但是 Orange 在他的系统中已经有代码添加了Facebook挂钩,因此,如果默认情况下将2.0引入到他的库中将会产生冲突.因此,我没有完全替换它,而是为 Apple 实例化了一次2.0,并并行地实例化了 Orange 附带的1.0版本,以便它可以使用正确的代码

When the end user updates Apple with the new release, she automatically gets version 2.0 of my library. But Orange had code in his system that added Facebook hooks already, so there would be a conflict if 2.0 was rolled in to his library by default. So instead of replacing it entirely, I instantiate 2.0 once for Apple and, side-by-side, instantiate the 1.0 version that shipped with Orange so it can use the right code.

该项目的重点是允许第三方开发人员根据我的代码构建系统,而不必依赖它们来保证系统的可靠性,并在需要时更新其代码.对于最终用户而言,一切都应该满足,并且在别人的系统中使用我的库时,更新我的库应该是一个简单的文件替换,而不是遍历和更改所有类引用.

The entire point of this project is to allow third party developers to build systems based on my code without depending on them to be reliable and update their code when they're supposed to. Nothing should break for the end user, and updating my library when used inside someone else's system should be a simple file replacement, not going through and changing all of the class references.

推荐答案

我决定采用一条稍微替代的路线.名称空间方法可以使用,但是您需要为该类的每个版本使用不同的名称空间.因此,它并不是真正可扩展的,因为您必须预先定义可用名称空间的数量.

I decided on a slightly alternate route. The namespace method works, but you need a different namespace for each version of the class. So it's not really scalable, because you have to pre-define the number of available namespaces.

相反,我已经为类和版本加载器/实例确定了特定的命名模式.

Instead, I've settled on a specific naming schema for the classes and a version loader/instantiater.

每个类将采用以下格式:

Each class will take the following format:

<?php
if( ! class_exists( 'My_Library' ) ) { class My_Library { } }

if( ! class_exists( 'My_Library_1_0' ) ) :
class My_Library_1_0 extends My_Library {
    ... class stuff ...
}
endif;

父级My_Library类实际上最终将包含一些特定于库的标识符-目的,兼容性声明等.这样,我可以执行其他逻辑检查以确保 right My_Library存在,然后声称My_Library_1_0确实是我想要的库的1.0版.

The parent My_Library class will actually end up containing a few identifiers specific to the library - purpose, compatibility statements, etc. That way I can perform other logical checks to make sure the right My_Library exists before moving forward and claiming that My_Library_1_0 is really version 1.0 of the library I want.

接下来,我将在主项目中使用一个加载程序类:

Next, I have a loader class that I'll be using in my main project:

<?php
class Loader {
    static function load( $file, $class, $version ) {
        include( $file );
        $versionparts = explode('.', $version);
        foreach($versionparts as $part) $class .= '_' . $part;
        return new $class();
    }
}

完成此操作后,如果要使用静态方法,则可以使用Loader加载类的两个实例或简单引用:

Once this is done, you can use Loader to load both instances of the class or simple references if you want to use static methods:

$reference = Loader::load( 'library.php', 'My_Library', '1.0' );

$loader = new Loader();
$instance = $loader->load( 'library.php', 'My_Library', '1.0' );

与我正在拍摄的名称空间版本不太相同,但是它可以正常工作,并减轻了我对最终用户破坏事物的担忧.我假设My_Library_1_0的两个不同版本是相同的,但是...所以仍然依赖于第三方开发人员知道他们在做什么.

Not quite the same as the namespace version I was shooting for, but it works and alleviates my concerns about breaking things for the end user. I am assuming that two different versions of My_Library_1_0 would be the same, though ... so there's still a dependence on third party developers knowing what they're doing.

这篇关于加载同一类的多个版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆