Php-o: metaprogramming PHP to give it a saner API
github.com
github.com
Why not simply implement a nice string class wrapped around ordinary strings with consistently parameterized chainable methods? The resulting code would be cleaner and more idiomatic (in a good sense). I don't think the "win" from doing this is worth the bother (unless maybe UTF8 support were managed as well).
But if you're asking about writing JS without jQuery and including support for old browsers (which I've also done), then fair's fair: you have to support PHP4 (which came out about the same time as IE6), and you don't get anything other than the standard library either.
For a non-trivial app, I'm not sure which of those is less pleasant.
I've also used JavaScript to automate Adobe's products, extend Cheetah 3d, build web apps in node.js, and develop games in Unity 3d. JavaScript is far from perfect, but it's a nice language.
Note that jQuery is great for fixing problems in the DOM APi, but it doesn't fix JavaScript (which has its own problems but no more than any other useful language). Much of jQuery is obsolete in modern browsers — events are handled fairly well in most browsers, and QuerySelectorAll replaces jQuery for most lookups. I don't like jQuery's iterators, but writing better ones is quite easy.
PHP's problems are with its libraries (themselves far more horrible than the DOM API) and also the language itself. I do find PHP useful but its problems far outnumber JavaScript's.
This is an experiment in meta-programming PHP to give it a saner API.
Sweet.
s() turns all the standard string functions into methods with identical behavior:
s($haystack)->pos($needle)
OK. Cool. Sounds good.
->preg_replace(), ->in_array()
Yep. Awesome.
The s() function also implements JavaScript's string API:
->charAt(), ->indexOf(), ->lastIndexOf()
...
......
.........
It's an interesting idea, but there's only one right answer here.
The point is, the standard libraries, especially in languages such as C++, Python or Javascript, are far from being the only libraries used by a project. Even if they follow consistent conventions, it can happen that an external library author does follow another convention. Using both libraries can lead to use multiple naming conventions in a single program, which doesn't help readability. It would be nice to be able to prevent this.
Beyond that, many of the functions take their ordering from their C counterparts.
The object stuff, kind of started to lose me. The chainables is cool but for me I could have stopped reading at s() and a() and been happy.
I think it'll definitely be worth experimenting with even if just for those two things, thanks for sharing!
The string comparison function provided as an example is 4 times slower than the code it's based upon, and 3 times slower than a completely equivalent multibyte-aware version.
The library is used about once every 3.5 lines, which feels less dense than most jQuery code I see, but that whole function runs 3 times slower than the plain MB-aware equivalent.
Some of the library functions might be implemented inefficiently but from a quick glance they're nearly all very thin wrappers.
Overhead from libraries like Symfony and ZF is quite acceptable since they offer much higher level features which you'd have to code yourself otherwise.
However making all your code (excluding I/O) run up to 3 times slower, just to add some syntactic sugar, is insane.
$len = mb_strlen("wtf");
# call function mb_strlen
$len = s("wtf")->len();
# call function s
# allocate string object
# instantiate string object
# call string ctor
# set property
# call method len
# get property
# call function mb_strlen
# destroy object
There's no way to use a syntax like this without either massive overhead, or massive changes in the engine.There is a somewhat similar experimental project - https://github.com/nikic/scalar_objects - but that's not meant for real world use either.
Personally I think the language, despite its flaws, does its job fine. I don't think it needs turning into Javascript-with-sigils.
This project is just replacing a function call with a method call -- it's all overhead.
Then, suddenly, however, there came a validation engine with annotations and reflection and whatnot. Huh? Isn't that a whole different thing? Why is this bundled with my nice little jQuery-for-PHP-scalars? It's not just that it feels like it's a different problem entirely and thus should be separate, the code feels different. Like it has a different philosophy behind it.
It looks pretty nice, but why can't I use the validation engine without PHP-o? Or the other way around?
This hurts so many principles and directions that PHP community is FINALLY diving into, like SOLID and stuff. Accepting simple things like strings are not objects is the way to improve how PHP devs build their stuff and start focusing on important things like defining de-facto libraries and joining forces to make them the best and most flexible available.
Don't get me wrong, the idea is pretty good (even if it's a simple try to mask procedural PHP functions)... but it seems like a swiss knife in the end.
Anyway, here are some suggestions.
1. "echo 'error message' and exit" isn't a particularly elegant solution, and in fact symbolizes everything that is wrong with PHP. What about throwing an exception instead?
2. The ability to specify the charset at object creation and convert to another charset later would be quite helpful, because nobody can remember all those mbstring functions. s('str', 'EUC-KR')->convert('UTF-8') maybe?
3. Why is O.php checking whether magic quotes are enabled? Since you're not even touching GET/POST variables, magic quotes have nothing to do with your library. Are you going to throw an error every time you discover suboptimal settings in the user's PHP environment?
4. Don't modify session settings until the user calls session_start(). They might not want to use your session handling functions, only your string and array functions. Simply including the script should have as few side effects as possible. This helps integration with existing apps.
5. Some of the methods that I'd really love to see in the string class are startsWith(), endsWith(), and contains(), copied straight from .NET. It sucks that I have to do strpos() === FALSE every time I want to check whether a string contains another string, or !strncmp($a, $b, strlen($a)) every time I want to check whether a string starts with another string.
6. While we're trying to clean up PHP's API, why not merge the case-sensitive and case-insensitive versions of string functions into a single method with an optional flag? This is another area where the API is terribly inconsistent, what with 'i's thrown in at random places and sometimes even 'case' to denote the case-insensitive version.
EDIT: Related to 5 and 6, I wrote a similar library back in 2010 for fun, which I put online just now [1]. It doesn't use the clever iterator interface that you incorporated into your library, but I do think that my method names make more sense.
Because O is currently designed to be the first thing code starts with, for green field programming, there was nowhere for the exception to throw to. Hence the exit.
Magic quotes are being checked because I have some ideas for how to improve the PDO API to prevent SQL injection. Those ideas have yet to turn into code for O though.
I've been contemplating turning this experiment into a usable library for production code, which would mean splitting it up into constituent parts, and making O.php a container for those parts. Then the separate parts could be used in isolation. I suspect the string and array handling by itself would be quite useful even in established projects, and it seems people here agree. Will start working on that.
Thanks for your suggestion about character set conversion. That would be a good addition. I'll add it.
A uncaught exception will end the script, just like exit() except with a stack trace and the ability to catch it if the end user wants that. There's really no excuse for any function to just exit().
> Magic quotes are being checked because I have some ideas for how to improve the PDO API to prevent SQL injection.
PDO prevents SQL injection through parameters; how do you plan on improving on that?
That's the whole point! Since it looks like O.php was intended as a framework for new projects rather than integration into existing code base, you could just tell people that they should use parameters when using O.php. No legacy code to support = all queries will be written from scratch anyway.
Please, don't reinvent the wheel of preventing SQL injection. It's a solved problem, and solving it again is boring. Bringing a bit of sanity to PHP, on the other hand, can be a much more exciting task.
The design of O is in part based on my experience using Zend Framework on large projects. I've learned that the only way to get people to write good code is not to educate them on the right way, but to make the right way the default / easy / lazy way. That's the issue with PHP as-is. It's possible to write good code in it, but it is decidedly not the default.
But, I see now that I will first ship what's in O already in a way that is reusable on other projects, mostly because I want to start mixing it with my own production code as well. After that I'll circle back to PDO.
Completely agreed. Binding each parameter manually, or even writing a simple prepare/execute pair, is probably too much hassle for somebody who is used to the utter simplicity of a mysql_query() function call.
Which is why, in one of my own home-baked libraries, I hide all of the prepare/bind/execute complexity behind a single method call:
$rows = DB::query('SELECT * FROM table WHERE col1 = ? AND col2 > ?', $param1, $param2);
Behind the scenes, it's PDO with prepared statements. On the surface, it's just as simple as mysql_query(), except you don't even have to worry about string interpolation. You can also pass the parameters as an array if you want to.I'm not saying that this is the best way to do it, but if the way you're planning to do it is anything that looks remotely similar (prepared statements and bound parameters behind the scenes), then you have my apologies for having been too cynical without seeing the actual code. On the other hand, if it's just a sanitizer based on a blacklist of special characters, I would persist in my criticisms.
I will stew a bit more on what approach (if any) is best for queries.
I prefer to abstract query building enough that most of the time I'm not constructing query text directly.
Personally I am unsure who drives contributions these days, is it individuals/ hobbyists/ small companies or is it being driven by large companies with large existing PHP codebases?
To be fair, that's copied from libc (and a lot of the other naming in the string library too): http://linux.die.net/man/3/strcasestr
certainly not something to use all the time, especially in perf-oriented code, but it's nice sugar.
Deleted comment
What about dojotoolkit or YUI library? I don't see how javascript is here to blame.
I personally say nuts to that. With all of the latest projects, PHP development is actually getting to be pretty non-shitty.
Note that I'm not saying PHP is great. It's a cesspool of language defects. However, it's success has merit.
"Hello World" is not world-like performance benchmark.
He's comparing "any decent php web framework" to Python or Ruby, because neither of those languages are used without frameworks to develop web-apps?
Then I thought about PHP, and how it compared with other languages. I went to Google and started searching:
influenced by gosling java
influenced by hickey clojure
influenced by matz ruby
influenced by Stroustrup C++
influenced by larry wall perl
and then finally:
influenced by lerdorf php
You look through some of those links and you notice a difference. A lot of people write about the brilliant things that have been said by Gosling and Hickey and Matz and Larry Wall and Stroustrup but no one ever cites Ramus Lerdorf as an inspiration, nor does anyone seem to think he has ever said anything especially brilliant or insightful. I'm sure if you dig you might find exceptions, but as a rough metric of who has influenced who, I think this reveals something important about how computer programmers perceive the quality of PHP and one of its core contributors.
(You could counter-argue that PHP has several core contributors, in which case, I would counter-counter-argue by asking that you please suggest a core contributor to PHP who is quoted with the same admiration expressed for the other architects that I've listed here.)
How about we talk about something new, such as the library this fucking post is actually about. If you really want to grind your ax against PHP (which we all generally agree is terrible), please make this its own post and submit it separately, so that we can actually talk about the submission.
I think he's said a few times on the record that he didn't really know anything about language design when he invented PHP.
Its creator, Fabien Potencier, is usually cited as someone bringing sanity and quality to the PHP world.
What also interests me is that the links on your HN profile seem to be Wordpress (built on PHP) related.