EAM*_*ann 6 php namespaces dynamic-code
假设我将代码库作为独立的PHP类发布.然后有人在他们的应用程序中使用该库的1.0版本.后来,我发布了该库的2.0版本,并且由于任何原因,同一个人需要在他们的应用程序中并排使用1.0和2.0,因为他或我打破了与新版本的向后兼容性.
如果类名不同,那么包含和实例化两者都很容易,因为没有命名冲突.但如果类名保持不变,我们会遇到问题:
include /lib/api-1.0/library.php;
$oldlibary = new Library();
include /lib/api-2.0/library.php;
$newlibrary = new Library();
Run Code Online (Sandbox Code Playgroud)
这不会起作用,因为我们无法使用名称加载两个类Library.另一个开发人员建议使用命名空间.以下应该有效:
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();
Run Code Online (Sandbox Code Playgroud)
不幸的是,这不是很可扩展.它适用于2实例情况(希望我不必首先使用),但要将其扩展为3,4,5或更多实例,您需要定义其他命名空间并设置,如果您没有首先使用这些名称空间,那就是一堆不必要的代码.
那么有没有办法动态创建命名空间,包含一个文件,并在一个唯一命名的变量中实例化该文件中包含的类?
让我补充一点澄清......
我正在构建一组库,供其他为几个CMS平台构建插件/模块的开发人员使用.理想情况下,每个人都会使用我的库的最新版本,但我不能保证这一点,我不能保证最终用户在新版本可用时总是升级他们的模块.
我正在尝试使用的用例是最终用户由两个不同的开发人员安装两个不同模块的用例:称为Apple和Orange.这两个模块都使用我的库的1.0版本,这很棒.我们可以实例化一次,两组代码都可以从功能中受益.
后来,我发布了一个小补丁到这个库.它的版本为1.1,因为它不会破坏与1.x分支的向后兼容性.Apple的开发人员立即更新了他的本地版本并推出了他的系统的新版本.Orange的开发人员正在度假,并没有打扰.
当最终用户更新Apple时,她会获得我库的最新维护版本.因为它是维护版本,所以假定完全替换版本1.0是安全的.所以代码只是从维护补丁中实例化了1.1和Orange的好处,即使开发人员从不打扰更新他们的版本.
甚至后来,我决定更新我的API,以便出于某种原因为Facebook添加一些钩子.新功能和API扩展改变了很多关于库的内容,因此我将版本升级到2.0以将其标记为在所有情况下可能不向后兼容.Apple再一次进入并更新了他的代码.没有什么破坏,他只是用/lib最新版本替换了他的文件夹中的库. Orange决定回到学校成为一个小丑,并且已经停止维护他的模块,所以它没有得到任何更新.
当最终用户使用新版本更新Apple时,她会自动获取我的库的2.0版本.但Orange在他的系统中已经添加了Facebook钩子的代码,因此如果默认情况下将2.0卷入他的库,就会发生冲突.因此,我不是完全替换它,而是为Apple实例化一次2.0,并且并行实例化Orange附带的1.0版本,以便它可以使用正确的代码.
这个项目的重点是允许第三方开发人员根据我的代码构建系统,而不依赖于它们是可靠的,并在他们应该的时候更新他们的代码.对于最终用户来说,没有什么可以破坏,并且当在其他人的系统中使用时更新我的库应该是一个简单的文件替换,而不是通过并更改所有类引用.
我决定走一条稍微不同的路线。命名空间方法有效,但您需要为类的每个版本使用不同的命名空间。所以它并不是真正可扩展的,因为你必须预先定义可用命名空间的数量。
相反,我已经为类和版本加载器/实例化器确定了特定的命名模式。
每堂课将采用以下格式:
<?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;
Run Code Online (Sandbox Code Playgroud)
父My_Library类实际上最终会包含一些特定于库的标识符 - 目的、兼容性声明等。这样我就可以执行其他逻辑检查,以确保在继续前进并声明它确实是库的 1.0 版本之前存在正确的标识符 我想。My_LibraryMy_Library_1_0
接下来,我有一个将在我的主项目中使用的加载器类:
<?php
class Loader {
static function load( $file, $class, $version ) {
include( $file );
$versionparts = explode('.', $version);
foreach($versionparts as $part) $class .= '_' . $part;
return new $class();
}
}
Run Code Online (Sandbox Code Playgroud)
完成此操作后,Loader如果您想使用静态方法,则可以加载类的两个实例或简单引用:
$reference = Loader::load( 'library.php', 'My_Library', '1.0' );
$loader = new Loader();
$instance = $loader->load( 'library.php', 'My_Library', '1.0' );
Run Code Online (Sandbox Code Playgroud)
与我正在拍摄的命名空间版本不太一样,但它有效并减轻了我对破坏最终用户的事情的担忧。不过,我假设两个不同的版本My_Library_1_0是相同的......所以仍然依赖第三方开发人员知道他们在做什么。