Strategy for developing namespaced and non-namespaced versions of same PHP code
I'm maintaining library written for PHP 5.2 and I'd like to create PHP 5.3-namespaced version of it. However, I'd also keep non-namespaced version up to date until PHP 5.3 becomes so old, that even Debian stable ships it ;)
I've got rather clean code, about 80 classes following Project_Directory_Filename
naming scheme (I'd change them to \Project\Directory\Filename
of course) and only few functions and constants (also prefixed with project name).
Question is: what's the best way to develop namespaced and non-namespaced versions in parallel?
Should I just create fork in repository and keep merging changes between branches? Are there cases where backslash-sprinkled code becomes hard to merge?
Should I write script that converts 5.2 version to 5.3 or vice-versa? Should I use PHP tokenizer?
sed
? C preprocessor?Is there a better way to use namespaces where available and keep backwards compatibility with older PHP?
Update: Decided against use of namespaces after all.
I don't think preprocessing the 5.3 code this is a great idea. If your code is functionally identical in both PHP 5.2 and 5.3 with the exception of using namespaces, instead of underscore-separated prefixes, why use namespaces at all? In that case it sounds to me like you want to use namespaces, for the sake of using namespaces..
I do think you'll find that as you migrate to namespaces, you will start to 'think a bit differently' about organizing your code.
For this reason, I strongly agree with your first solution. Create a fork and do backports of features and bugfixes.
Good luck!
This is a followup to my previous answer:
The namespace simulation code got quite stable. I already can get symfony2 to work (some problems still, but basically). Though there is still some stuff missing like variable namespace resolution for all cases apart from new $class
.
Now I wrote a script which will iterate recursively through a directory and process all files: http://github.com/nikic/prephp/blob/master/prephp/namespacePortR.php
Usage Instructions
Requirements for your code to work
Your classnames mustn't contain the _
character. If they do, classnames could get ambiguous while converting.
Your code mustn't redeclare any global functions or constants within a namespace. Thus it is ensured that all your code may be resolved at compile-time.
Basically these are the only restrictions to your code. Though I should note that in a default configuration the namespacePortR will not resolve things like $className = 'Some\\NS\\Class'; new $className
, because it would require inserting additional code. It's better that this is patched up later (either manually or using an automated patching system.)
Configuration
As we have made the assumption that no global function or constant is redeclared in a namespace you must set the assumeGlobal
class constant in the namespace listener. In the same file set the SEPARATOR
constant to _
.
In the namespacePortR change the configuration block to satisfy your needs.
PS: The script may be provided a ?skip=int
option. This tells it to skip the first int
files. You should not need it, if you have set the override mode to intelligent.
Here's what I've found:
Doing this with regular expressions is a nightmare. You can get most of it done with just a few simple expressions, but then edge cases are a killer. I've ended up with horrible, fragile mess that barely works with one codebase.
It's doable with built-in tokenizer and simple recursive descent parser that handles only simplified subset of the language.
I've ended up with rather ugly design (parser and transformer in one – mostly just changing or re-emitting tokens), because it seemed too much work to build useful syntax tree with whitespace maintained (I wanted resulting code to be human-readable).
I wanted to try phc
for this, but couldn't convince its configure
that I have built required version of Boost library.
I haven't tried ANTLR for this yet, but it's probably the best tool for that kind of tasks.