Oct 8, 2010

PHP Preprocessor

I've thought of a random cool project, but this time instead of starting out on it, getting halfway through and then abandoning it, I figure I'll put it up for public discussion where others can throw in their two cents, tell me if such a thing already exists, or tell me I'm a moron and that it's a stupid idea (actually there will be people who will always say this, regardless of what the idea is).

I want to add some sort of preprocessor to PHP, to extend the power of the language. It seems a bit silly to add a preprocessor to something that is already a preprocessor, but I figure it is more practical to build this thing as something that outputs a language that is already very widely supported - my main incentive for this project is to then use it for PHP sites and put onto servers that already support PHP without needing additional software.

My main inspiration for such a project is from Ruby on Rails. See, Rails has a lot of good ideas, but many of them are easily translatable to PHP and other languages. You can use PHP's __call(), __get() and __set() methods to mimic a lot of the things that Rails does - I do this in MinMVC for model objects already.

What I think is much more powerful is the ability to use code to manipulate classes (aka metaprogramming). In Ruby I can do stuff like this:
class MyClass
  awesome_function_that_manipulates_MyClass

  ...
end
In PHP you can't do this. While PHP has a reflection API (I haven't actually used it much, so I can't comment on how good it is) it appears to be a read-only API. You can get information about classes and methods, but you can't modify them. You can't stick random methods into a class at run-time (unless I haven't read the PHP Reflection documentation properly). So you can't do something like this in PHP:
class MyClass
  has_many :users
The has_many method would add certain methods to MyClass to make it nice and easy to interact with the users that this class has. While you can mimic this functionality using some __call() hackery, I think adding some sort of metaprogramming capabilities would make this much simpler and more maintainable.

What this preprocessor would do is scan for files that end with .m.php and convert them to .php files. The project would involve writing a parser that would scan for preprocessor blocks and execute them. The code in the preprocessor blocks would also be PHP, so you can do whatever you like in there. The key difference would be the use of $this: if you're inside a class, $this would refer to a Class object that represents the current class. So you would write something like this:
class MyClass {
#begin
  $this->has_many("users");
#end
It's not nearly as elegant as the Ruby version, but that's ok. What this would do is the PHP preprocessor would execute the code in between #begin and #end and output some sort of PHP code to affect MyClass, like add methods called getUsers(), addUser(...), etc.

Quick aside on the use of the extension: I use .m.php instead of .phpm or something because Apache has a tendency to just serve files if it doesn't recognize the extension, which is a security risk. If it ends with .m.php, Apache will just execute it as a PHP file and fire out a PHP error when it sees weird stuff.

I'm still thinking about the details as to how you might add methods to $this, so that people can write add-ons. It might look something like this:
class_function has_many($what){
  ...
}
Who knows. Any comments on this idea?

2 comments:

Julien said...

I think it's a pretty interesting idea.

I remember googling for something like this and found nothing.

Who knows, it could become a kind of Objective-PHP! ;)

Sean Coates said...

Andrei and I came up with this after Confoo last year (-:

http://github.com/andreiz/prep

S