Let's assume we have a PHP project with dependencies A and B each depending on PHP library X, but in a different version.
Usually, one would use a PHP dependency manager such as composer which would either resolve this conflict by including X in a version compatible to both A and B or display an error if the conflict cannot be resolved.
Now, many PHP applications allow their users to install plugins simply by uploading pre-bundled packages and extracting them to a specific plugin directory.
If A and B were such pre-bundled plugins and both would bring their own version of library X, we might run into problems since no dependency manager is available to select a compatible X for us or display an error in case there is none.
To prevent any such conflicts caused by the inability of PHP to have library X being loaded twice with different version into the same namespace, we could put A's X and B's X into different namespaces (which might be hard to do automatically as we would need a PHP parser for that...).
My question is:
How would you solve this problem? Can you recommend this approach or is there a better solution?
There is no solution without changing the code. If two versions of ´\Vendor\AnyClass´ do exist in the filesystem, and code is executed to use them both, either an error appears because redeclaring that class is not allowed, or because the expected class is incompatible. It will only work if the interface of the class is implemented the same, i.e. the two codes are compatible. The problem of compatibility is complicated if it isn't only that one class, but an entire tree of objects that may react badly to mixing classes from different versions, even though they offer a compatible interface.
Changing the namespace is changing the code. Who's responsible for that? I can think of some automatic code parser that would be able to add a specific namespace prefix for each plugin, but that task hasn't been done to my knowledge in PHP. The Java guys in my company made some remarks that such a problem has been solved there, but I have no details.
Also, it doubles your code base, and the duplicated code has to share only the one opcode cache you have.
I know that the core developers of Wordpress are still struggling with this problem. There are some coded suggestions of how to use Composer for dependency management (i.e. plugins and their dependencies), but I don't think they made enough progress for now.
Essentially you have two choices: 1. Create a code namespace prefixer, parse all the files belonging to a plugin (so the plugin author has to include his dependencies somehow), change the code, live with the code duplication, and see what awaits you when it comes to debugging. The downside is that no code outside of that plugin will be easily able to use the plugin code directly because that would mean to know the created prefix. 2. Implement some form of dependency management, preferably using Composer, and don't change the namespaces.
Update: I consulted my Java co-workers again, and they basically made the same statement about Java that I made about PHP: You cannot have two different versions of a class under the same class name, and there is no "magic" even for Java but renaming the class to a different namespace.
Related
I am developing a plugin that used composer.. meaning it has a vendor folder inside the plugin folder which includes Guzzle HTTP dependency
On wordpress site we installed this plugin, there is an existing plugin that has Guzzle HTTP
Now when we activate this plugin i am getting an error something like this:
Fatal error: Cannot redeclare GuzzleHttp\uri_template() (previously declared in /nas/content/staging/project/wp-content/plugins/my-plugin/vendor/guzzlehttp/guzzle/src/functions.php:17) in /nas/content/staging/project/wp-content/plugins/other-plugin/includes/lib/aws-sdk/GuzzleHttp/functions.php on line 31
I tried installing Plugins Load Order to force the 'other-plugin' to load first before 'my-plugin'
currently the error is happening on the other-plugin's resources.
this way, The error will yield in our autoload and we can catch that.
unfortunately.. Plugins Load Order did not work..
any ideas how to solve this?
Welcome to WordPress hell. We have 2018 and WordPress still does not have any dependency management and still didn't notice Composer existence.
WordPress ecosystem simply relies on assumption, that functions/classes names of plugins/themes should be unique. Obviously distributing popular 3rd-part Composer libraries with your plugin/theme is asking for trouble - it is easy to get names collision when other plugin is doing the same. There is no good way out of this situation.
If you want a bulletproof solution for standalone plugins, you should prefix namespaces of every package in your vendor directory with plugin prefix, for example myplygin\vendor. Then GuzzleHttp\Client becomes myplugin\vendors\GuzzleHttp\Client, so there is no risk of name collisions. This will require some work to write script for this (or you may use some existing solutions, like humbug/php-scoper), and you may get many duplicated dependencies (10 plugins may bring the same library 10 times, but with different namespaces), but this is the cost of integrating modern tools and patterns into outdated software.
If you're writing this plugin for yourself and you're controlling final installation, you may try to use Composer for installing WordPress and its plugins. You still may need to fix 3rd-party plugins (via forking) if they're have bundled some composer library, but in the long run it should simplify many things and you may avoid duplicating libraries for every plugin.
By design, PHP and Composer assume that you develop and distribute your code in a controlled environment. However, when you publish plugins on WordPress or modules on Joomla, you distribute the code on systems where you don't have control over what other authors install. This situation can result in name collisions such as Cannot redeclare GuzzleHttp\uri_template()....
To prepare your code for multi-vendor setups, you must prefix the PHP code to avoid name collisions or version collisions (the same library with a different version is loaded first). For instance, Guzzle is a well-known and widely used library, so if you publish a plugin including it, you must prefix it before distribution.
At first glance, you may think that prefixing only the namespaces would get the job done. But other named elements such as global functions and traits must also be prefixed to avoid all possible error types.
To prefix PHP code, there are tools or services to execute the task:
humbug/php-scoper. Prefixes all PHP namespaces in a file/directory to isolate the code bundled in PHARs.
Interfacelab/namespacer. Namespacer allows you to rename the namespace of any composer packages. It works by adding a namespace prefix to all of the namespaces. Namespacer also prefixes the package names. It then generates a folder called "lib" that you can safely include in your WordPress plugin.
coenjacobs/mozart. Developers tool for WordPress plugins: Wraps all your projects dependencies in your own namespace. This prevents conflicts with other plugins that load the same dependencies but in different versions.
PHP-Prefixer. It's an automated online service powered by a complex rule-based system to apply prefixes to Composer dependencies. In the composer.json, you just define the prefix to apply without worrying about the nitty-gritty details.
Disclaimer: I'm the lead PHP-Prefixer developer.
This is not suggested but use it if you must
function this_plugin_last() {
$wp_path_to_this_file = preg_replace('/(.*)plugins\/(.*)$/', WP_PLUGIN_DIR."/$2", __FILE__);
$this_plugin = plugin_basename(trim($wp_path_to_this_file));
$active_plugins = get_option('active_plugins');
$this_plugin_key = array_search($this_plugin, $active_plugins);
array_splice($active_plugins, $this_plugin_key, 1);
array_push($active_plugins, $this_plugin);
update_option('active_plugins', $active_plugins);
}
add_action("activated_plugin", "this_plugin_last");
I make use of this library which is a more maintained version of mozart: https://github.com/BrianHenryIE/strauss
It lets you set a namespace prefix for your vendor libaries of choice and add them to a separate library which you can then autoload into you project.
It also has a lot of other useful features.
I'm guessing there's a function at GuzzleHttp/functions.php on line 31 so you can use something like that:
if (function_exists('Do_Something')){
echo "Function Exists";
}else{
echo "Function Not Found, This name Can be used!";
}
or you can use is_plugin_active function to check if the plugin is already installed. In that case, you can ignore including the files
https://codex.wordpress.org/Function_Reference/is_plugin_active
I am using these two libraries from composer
"require": {
"alterfw/php-form-generator": "^0.1.2",
"rlanvin/php-form": "dev-master"
},
Biggest issue is both has the same class name Form with no namespace defined. Now no matter either I am instantiating only one class or both on the same page it is giving me an error as below
Fatal error: Call to undefined method Form::create() in...
create method is to generate form markup from alterfw/php-form-generator library.
So when I tried this
$form = Form::create('path-to-action.php');
$form->add(Form::text('settings')->setLabel('Settings')->setValue('None'));
echo $form->render();
Giving me the error mentioned above. For me it is difficult to understand why even I hven't instantiate another class it is still giving error.
I a also not so much familiar with composer to dig into myself without any guide.
So is there any way so I can use both libraries at the same time?
Tip: Packages without a vendor namespace are a bad practice, as you can see here. I recommend creating an issue for both packages saying they should really add a vendor namespace.
The problem here is that as soon as you use Form in your code, the class isn't already loaded and Composer's autoloader is executed. As it has 2 packages to load the class from, it'll pick the first registered autoload rule. This results in the wrong Form class: Problem!
You can swap the packages position in your composer.json, but this means the other class is no longer usable.
Another solution is to require the class yourself by using the require()/require_once() PHP functions. This is a bad practice and also means you can only use one of the 2 Form classes (requiring the other form class after one is already required results in a "Class with name "Form" already exists" PHP error).
TL;DR: You can only use one of the 2 packages in the same application.
There is really no shortage of form validation libraries. Every single framework should have one component for this.
So I'd recommend selecting your libraries carefully.
We have here the first library "alterfw/php-form-generator", which is 4 years old, being unmaintained since then, until it got forked 4 months ago with adding composer.json. Four years ago, PHP 5.2 was still common, so it is no real surprise that this code has no namespace. It also has no real documentation, because the link in the readme file is dead. The forked repository of this library does not allow creating issues. :( I doubt that the upstream repository will care about anything after 4 years of not maintaining it.
The second library "rlanvin/php-form" seems to be tied to non-public code. You opened a ticket to add namespace to that one class, and effectively got rejected (saying that the maintainer will not add namespaces because it is more convenient for him, but you could edit the file yourself to add it simply does not cut it). Packagist shows that this library has 31 installs. It's not completely right to say that "nobody uses this code", but it is very close.
If your task is form validation and form generation, I'd say that either the Symfony or Zend components will likely perform that task very well. There probably is no need to resort to libraries that "nobody" uses, and that do not apply modern development methods like namespaces (available since PHP 5.3, which was released in 2009).
I'm writing a WordPress plugin. (However, this is not a WordPress-specific question - this challenge could arise in any PHP codebase which uses a plugin pattern.)
My plugin makes use of a popular third-party library, which is also used by a lot of other common WordPress plugins.
Obviously, if both my plugin and another plugin load their own copies of this library, PHP is going to throw an error, because I'm trying to redeclare an already-declared class.
How can I avoid this conflict? Before you answer, please consider why I've rejected these obvious options:
I could rename the library's classes, or put them in a new namespace. I don't like this because it involves modifying the library files. If I later need to upgrade to a newer version of the library, it would overwrite my modifications. And it's just generally an inelegant PITA.
Before my plugin actually includes the library, I could use class_exists() to make sure it hasn't already been included. There are two reasons I don't like this option:
Another plugin might use a different version of the library that has a slightly different API. This could cause my plugin, or the other plugin, to break (depending on which version of the library gets loaded first).
More importantly: the library in question contains multiple class definition files, and each child class includes its parent. Say that my plugin includes ChildClass1.php (which, in turn, includes BaseClass.php), and another plugin includes ChildClass2.php (which also includes its own copy of BaseClass.php). class_exists() doesn't help me here - there's no way that both plugins can include the ChildClasses they need without causing a conflict.
So: how can I make use of this library without running into one of these problems? Is there some way to override the library's namespace at include time (without modifying the library)? Is there some other solution that I'm overlooking? Seems like this must be a pretty common situation.
I'm answering my own question. (I can't believe I was this naïve only three years ago!)
This problem (among others) is exactly why dependency managers exist. (If you use npm, then you're already familiar with dependency management.)
In the PHP world, Composer is the standard tool for dependency management.
However, WordPress isn't really built to play nice with dependency managers (or with source control). In fact, WordPress actively fights against these practices.
There is a project called Bedrock, which tries to contort WordPress into something that's compatible with modern development practices. I haven't used it – but if you must use WordPress, it's worth investigating.
tl;dr:
The solution to this problem is to use a dependency manager, such as Composer.
But, WordPress simply isn't compatible with Composer – it'll fight you every step of the way, and you'll create more problems than you solve.
Unless you use Bedrock's version of WordPress – which is designed to work with Composer.
But, at that point, you might as well ditch WordPress, and adopt a CMS platform that's sanely engineered in the first place – and doesn't have to be twisted and tortured into cooperating with industry-standard practices.
In the Symfony 2 docs it's said:
A bundle should not embed third-party libraries written in JavaScript, CSS, or any other language.
Then how should I do that? I want to install Twitter Bootstrap, DataTables, and many other things as dependencies using Composer. But the only way I can think of is creating a bundle and embedding them.
What is the correct way to do this?
You should use Bower by Twitter. It is a package manager for HTML, CSS and Javascript. It was created to address this very issue you are having.
EDIT:
As of now, there are very good package managers for JS Libraries such as Bower, Jam or Component.
Versioning system
Semantic Versioning - Composer advises to use the semantic versioning system. It uses a X.Y.Z setting, in which X is the major version, Y is the minor version and Z is the patch version. Y and Z should always be backwards compatible while X reflects changes in code which MIGHT break backwards compatibility.
Embeding
Embeding should be read as copy and pasting the code (and binary) as part of your library, rather then requiring it as a third party (vendor) package/bundle. Its like including query.js in a resource folder or copying and pasting propel code to a folder inside your bundle.
Why not embed 3rd party libs
A bundle should not embed third-party libraries written in JavaScript, CSS, or any other language.
This statement comes from a best practice point of view. Embeding (as in copy/paste) third party libraries of any kind (PHP libs especially) is usually not a good idea. For instance, imagine that BUNDLE A uses LIBRARY FOO v1.4.1, and BUNDLE B also uses LIBRARY FOO but with a different version v1.5.2. If any of the BUNDLES (A or B) embeds FOO lib, they might (most probably will) become incompatible. For instance, php classes and functions cannot be redeclared. Any of the bundles can, of course, use workarounds to mitigate this problem, such as namespacing their version of FOO or autoloading rules, but this can rise other problems as well besides surely increasing memory usage as there are 2 versions of the same thing parsed by PHP.
If a PHP package does not follow this best practice, the errors that arise are usually easy to spot (with error: cannot redeclcare function blablabla). With Javascript Libraries, however, that is not true. You can redeclare functions (as they are object properties). So if now FOO is a JS Lib instead, and BUNDLE A and B embed them into their libraries, when they are included, strange problems can arise. For instance, a function can be redeclared that lacks a crucial functionality for one of the bundles and break it.
Symfony is a PHP framework.
It deals with PHP libraries/bundles. Symfony advises to require a library as dependency instead of embedding it since it uses Composer as a Package manager, which takes care of downloading and loading the require packages. As far as I remember, when 2 bundles/packages use the same library, if they have different version requirements, the most actual is used, unless its backwards incompatible. Composer then reports a conflict that you have to manually resolve.
However... There is no way to handle javascript libraries properly. That's because Composer is a package for PHP libraries. You can workaround this in two ways I can think of: (there are probably more and best ways to handle this, I just thought of these two, read them as suggestions)
Create a PHP wrapper around the javascript library and including it (although this potentially creates the same problem if another bundle decides to do the same thing but giving the package a different name)
Creating a bundle which requires the javascript library as a third party dependency through composer. Since the javascript library won't probably have a composer.json file in it's repository (sometimes they live as a standalone minified file), this can be accomplished by creating a custom composer installer, forking the javascript repository (in gitHub for instance) adding a composer.json to it, etc... However, you will need to constantly maintain and upgrade the said library, which can be troublesome.
You will have to keep in mind that:
JS and CSS libs have to be exposed publicly, so that the client can access it (security considerations)
Symfony is a PHP framework and deals with server-side packages. JS/CSS are client side. This as to be taken in consideration so it works properly.
One of the main ideas behind symfony (as with other PHP Frameworks) is code reusability within and between projects. Pure Javascript Library are reusable in themselves. They are usually self contained. Besides, there is no real gain in "bundling" a JS library from the server side. You don't need any kind of bundle to achieve reusability.
My Approach
Since the composer system is so appealing, specially when deploying bundles/packages/libraries to other people, my approach to using third party javascript/css libraries was to create a dependency manager specific to JS/CSS that other packages/bundles could rely on to take care of their JS/CSS dependencies without worrying about this.
My sugestion
If you are planing to release your project to the public, namely as a symfony bundle, you should plan carefully how to approach this.
If your project is self contained (personal use or to a client, not widespread use) then this has much less relevancy since you (the programmer) have total control in what third party tools you use and include in your project. These are just best practice "suggestions" to avoid
future problems.
I am building a PHP CMS from the ground up. There is one super-core file within my system which I currently have automatically importing all other packages and classes that make up the core of the system. On a typical page, only a few of these classes and methods are used.
Considering the load require_once() puts on a server to include all of these files, and the time a user must wait for the page to load, I am wondering which path I should take:
Keep the super-core as-is and automatically include all of the system core for each page that includes this core file.
Use the super-core to include only essential packages, such as database management, and import additional packages/classes on an as-needed basis.
Could someone please let me know which of the two options are the best, as well as a brief overview of its pros and cons?
Thank you for your time!!!
You're asking a question about which is the best load-strategy. This is often discussed related to auto-loaders.
As with any strategy, there are pros and cons. Including all files can save you the hassle to forget one. An autoloader on the other does not forget a file as well.
However you must not always use the one or other strategy but if you implement multiple you can choose as needed. For example if you develop your CMS things might change often. But if the CMS is installed on a server, that version does not change often.
So in production a strategy to combine all core libraries into one file and require them on startup can be a benefit depending on how much load a server has.
For an easy way to build own systems I can propose an autoloader. If you line-up your classes file by file they will get automatically loaded in the moment you use the class.
When you achieved a certain step in development you actually know what core files are or not. You can then load these by default so the autoloader would not be triggered any longer for them.
Earlier this year, I came upon this exact problem while developing a framework in PHP.
I considered the pros-cons and here's my evaluation:
Option 1 - Front Controller Pattern script include all other scripts
Advantages
Inclusion of packages are done within one script; you can see what files are included what are not at one glance.
Inclusion of a particular package is always called once, there is no overhead.
Disadvantages
Consider the case of such:
We have two classes Rectangle and Shape. Rectangle is a child class i.e. extension of Shape. However the core script includes the classes alphabetically. Thus when Rectangle is included, Shape is not found and PHP will throw an error.
Rectangle class:
class Rectangle extends Shape{
}
Shape class:
class Shape{
}
more overhead when everything that is not needed is also loaded into the memory.
Option 2 - Load main packages, then load other packages as-needed
Advantages
Files are only included when needed. Reduces overhead in another way
Solves the problem mentioned in Option 1.
You are able to concentrate on what each package requires from other packages and simply just load them
Disadvantages
Overhead as multiple requests for a particular package may occur.
Package inclusion is done in every single file.
Programming code is for human. Therefore to make things more logical and breaking down the problem, I chose option 2 to go for the framework.
Don't load what you are not going to use. Implement an autoloader or deepen your require_once's.
Even if the performance is neglect-able, less files includes will increase your ability to quickly hunt down bugs and determine the flow of your application.