Download multiple versions of the same class

Say I'm releasing a code library as a separate PHP class. Then someone uses version 1.0 of this library in their application. Later I release version 2.0 of the library, and the same someone for some reason should use both 1.0 and 2.0 side by side in their application, because either he or I violated compatibility with the new version.

If the class names are different, just include and create an instance of both, because there is no name conflict. But if the class names remain 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(); 

This just won't work, because we cannot load two classes named Library . One alternative from another developer suggested using 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(); 

Unfortunately, this is not very scalable. It will work with the situation with two instances (which, I hope, I will not need to use in the first place), but for scaling up to 3, 4, 5 or more instances you will need to have additional namespaces defined and configured. If you are not using these namespaces in the first place, this is a bunch of unnecessary code.

So, is there a way to dynamically create a namespace, include a file, and create an instance of the class contained in this file in a variable with a unique name?


Let me add a few more explanations ...

I am creating a set of libraries that will be used by other developers who create plugins / modules for several CMS platforms. Ideally, everyone will always use the latest version of my library, but I cannot guarantee this, and I cannot guarantee that the end user will always update their modules when new versions become available.

An example of the use I'm trying to work with is one where the end user installs two different modules by two different developers: name them Apple and Orange . Both modules use version 1.0 of my library, which is great. We can instantiate once, and both sets of code can take advantage of the functionality.

Later I released a small patch to this library. It is version 1.1 because it does not violate compatibility with the 1.x branch. An Apple developer immediately updates his local version and pushes a new version of his system. Developer Orange is on vacation and not worried.

When the end user updates Apple , she receives the latest release of my library. Since this is a maintenance release, it is assumed that it will completely replace version 1.0. Thus, the code only creates version 1.1 and Orange from the service patch, although the developer never bothered to update his release.

Later, I decided to update my API in order to add some Facebook hooks for some reason. New features and API extensions have a big impact on the library, so before version 2.0 I deliver it as potentially not backwards compatible in all situations. Once again, Apple enters and updates its code. Nothing broke, he just replaced my library in his /lib folder with the latest version. Orange decided to return to school to become a clown and stopped supporting his module, so he does not receive any updates.

When the end user updates Apple with the new version, it automatically receives version 2.0 of my library. But Orange had a code in its system that already added Facebook hooks, so there would be a conflict if, by default, 2.0 was loaded into its library. Therefore, instead of completely replacing it, I create an instance of 2.0 for Apple and, side by side, I create version 1.0 that ships with Orange so that it can use the correct code.

The whole point of this project is that third-party developers can create systems based on my code, regardless of being reliable and updating their code when they should. Nothing should break for the end user, and updating my library when used inside some other system should be a simple file replacement that does not go through and does not change all class references.

+6
source share
3 answers

I decided a slightly alternative route. The namespace method works, but each version of the class requires a different namespace. Thus, it is not very scalable because you must first determine the number of available namespaces.

Instead, I decided to use a specific naming scheme for classes and the / instantiater version loader.

Each class will have 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; 

The parent class My_Library will actually contain several identifiers specific to the purpose of the library, compatibility operators, etc. That way, I can perform other logical checks to make sure that the correct My_Library exists before moving forward and claiming that My_Library_1_0 indeed the version 1.0 of the library I want.

Then I have a bootloader class that I will use 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(); } } 

Once this is done, you can use Loader to load both instances of the class or simple links 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' ); 

Not exactly the same as the namespace version I shot at, but it works and alleviates my concern about interruptions for the end user. I assume that two different versions of My_Library_1_0 will be the same, though ... so there is still a dependency on third-party developers, knowing what they are doing.

+3
source

So, is there a way to dynamically create a namespace, include a file, and create an instance of the class contained in this file in a variable with a unique name?

Yes, such a method exists. You can do whatever you want with the eval and stream handlers. But this is the wrong practice and the wrong approach - you can try using the factory method (the code is not verified - it shows only an example):

 <?php if (!class_exists('Library')) { class Library { public static function create($version) { if (class_exists($c = 'Library' . $version)) return new $c(); return null; } } } class Library1 { } class Library2 { } ... 
0
source

Let the user select the version, then download the api file accordingly

The file name must be dynamically defined, for example:

 include('/lib/api-'.$versionId.'/library.php'); 

if version -1.0 how wise

Make sure that user input is converted to a single decimal character float and nothing genius.

-1
source

Source: https://habr.com/ru/post/886713/


All Articles