OK, here's the thing: this is only the entrance of the rabbit hole.
reddit.com
reddit.com
Then, something happened. Yes, the language matured, but I also started using application frameworks in PHP, which addressed many of the issues I had with PHP, and then I built an MVC framework from scratch, based on what I'd learned.
Now, I just don't care. I'm not going to defend PHP as a good language, not even it's creator will do that, but when people go on about how terrible PHP is, my first thought is "well, then use it more, and eventually you'll stop caring."
I stick with PHP, specifically for open source, because of it's install density, because it is extremely flexible, and because I know all it's weird quirks and inconsistencies so well that they no longer bother me. I wouldn't mind switching to a more structured and consistent language if it came up, but I don't see PHP as a limitation for anything I want to accomplish, and haven't for a very long time.
And anyways, terrible code is terrible code, and when I think about having to delve into projects that are spaghetti, or procedural, or have no separation of concerns, I don't blame the language for my frustration.
But I worked out how to adopt the new structured style to the limitations of the language, and learned a lot. Better languages make better tools, of course, but it's the hacker's attitude that really matters.
At the same time, I have to use Joomla at work and I sometimes catch myself with a partially-tied-off noose around my neck.
It really comes down to what framework you choose.
Against off-by-one errors, abstain from any from of loop.
For the real hard problems, like deciding whether your program has crashed or just takes a long time, give up.
That's why they had to name it Forth.
http://discuss.joelonsoftware.com/default.asp?joel.3.219431....
Unfortunately you have to get them from a FactoryFactory.
I never even think about high level stuff like "what language should I code in" anymore. It doesn't matter to the end user. CodeIgniter allows me to do anything I want, elegantly and with a small footprint.
It's a means to an end and eventually like you said, you stop caring about the "means". It's the "end" that matters - i.e. how well you execute. Using RoR (for example) as opposed to PHP has zero impact on that.
You might also argue that at scale PHP may eventually come back to bite you, but your not at scale at the moment and the majority of us should be thinking about the best way for us to deliver v1, not the best way for us to deal with 1 million users.
This year, I had to maintain legacy PHP code powering a custom calendar & training-session signup app. Notable horrors I encountered:
- Despite being written by a programmer in the employ of a major Californian company providing security solutions to corporate customers, all passwords were stored in plaintext in the database. The database itself was password-protected by a guessable variation on the company’s name (seriously).
- The ancient register_globals directive was on — not just on, but relied upon. As in, when I moved the code to a server with the directive off (e.g. any modern hosts), all the forms broke. For those who haven’t heard of this, er, “feature,” it means that any variable in the request, be it a cookie name, a GET parameter, or a POST key (that is, the name of an input field on a web form, typically) automatically becomes a global variable in the PHP script set to the provided value. So I could manipulate my DOM, add an <input> field named, say, "is_admin", set its contents to "1", and voilà! $is_admin is now truthy.
- Nothing was ever properly escaped. Not the database, not email headers, not page output.
- And of course, code and HTML were strewn together willy-nilly, with lots of repetition and insane spaghetti-code execution. Let’s just say it was non-trivial to skin all the pages in the app.
I know and you know PHP doesn’t force anyone to commit these sins. But for backwards-compatibility reasons, it still permits them… and I find it hard to believe absolute stinking dangerous messes like this are more common in other modern platforms.
When using Python's Django (mostly a default nowadays) all string output in templates is escaped by default (you've got to make it explicit if you don't want it). Also in Django all forms submitted are protected against csrf attacks by default.
In no case above are you allowed to do "; drop table users", since most ORM's that were made by people with brains can detect that you want to do a DDL when a SELECT is expected. You've got to use the raw Python DB API for that, and that's not easier than just going along with what the framework gives you.
E.g. Django 1.2 added raw queries, but this will trigger an error since it is not a plain SELECT:
Users.objects.raw("DELETE FROM users")
Without a framework like Django, you can't really do web development in Python without blowing your brains out.Every other popular web platform isn't like PHP which is a language specifically made with clear hooks for processing requests / spitting out HTML (right there, in the language).
Heck, you can't even write a PHP script that doesn't contain a "<?php" tag.
I'm not saying that bad code isn't universal, but PHP makes it a whole lot easier to do stupid things and not in a Lisp-esque way.
Actually while I won't defend register globals in 2010, back in 1998 (am yes, I wrote PHP code in 1998) when nobody understood web development really (do we even today?) it was a handy feature, that prevented much line noise on pages that were (back then) usually composed of html with a few <? ?> tags and code in between, pretty much the way javascript was on pages until a few years ago. It was only as the php became heavier and was moved in to common include files and later into libraries that the usefulness went away (but the potential issues remained).
Edited for clarity
It isn't something you can easily debug and it is complicated. That said, it isn't the gates to hell that it is represented as. It's a tool, and it can make code cleaner if you want it to.
function __tostring(){ $items = ['title','header','comment'] foreach($items as $item){ echo $this->$item; } }
Make that list of class variables much longer and you start to see the benefits in certain cases.
There are times when I do miss variable variables.
def print_string(self):
items = ['title', 'header', 'comment']
for item in items:
print getattr(self, item)
Where "getattr" is just a pretty protocol for calling ... self.__dict__[item]
This extends to whatever you want, including members of namespaces (like declared classes, functions, other namespaces, etc...) $"test";
It turns out that '$' can only operate on an identifier or another '$' expression. The '${...}' syntax, aside from being more readable and less likely to be accidentally encountered, is more like an operator: ${"test"}; // equivalent to $test
The decision to keep (and only warn against) unescaped strings past the introduction of an incompatible feature (constants) is inexcusable. It creates oddities: $test = 'foo';
$foo = 42;
echo $test . " ${test} " . ${test} . " " . $$test . "\n";
This generates a notice and prints, "foo foo foo 42". But then: $test = 'foo';
$foo = 42;
define('test', 'foo');
echo $test . " ${test} " . ${test} . " " . $$test . "\n";
This will print, "foo foo 42 42". (Note also the difference between the meaning of ${...} within string interpolation versus outside of it.) Is this all understandable? Sure. Is it good? No.It's so easy to turn those warnings into exceptions. I don't think I've seen any project in the wild that does anything meaningful with unescaped strings.
set a b
set $a c
And while it took some getting used to, one could do it in a disciplined fashion, with a proc, and so create/set only certain variables in a calling proc. One did not have to spatter the whole scope with who knew what variables when pulling stuff out of an associative array.
# Ruby
a = "some text"
b = "a"
eval b # => "some text"
# Python
a = "some text"
b = "a"
eval(b) # => "some text"
# Javascript
a = "some text";
b = "a";
eval(b) // => "some text"
I've found the the more "quick and dirty" a language is, the simpler it is to use variable variables. And I don't mean quick and dirty as an insult. Bash supports this, and while I consider it quick and dirty, you can pry bash from my cold dead hands. # Bash
a="some text"
b="a"
echo ${!b} # => "some text"
Having said all that, using variable variables is a great way to piss off whoever has to maintain your code, so use them sparingly, and only when appropriate. There is little or no opportunity for context with variable variables. To add insult to injury, variable variables can result in gaping security holes as well. Think of the implications were an attacker able to substitute the value of the variable variable in any situation where the output is sent to the client. The attacker could randomly guess at variable names, dumping all manner of information. Anything in the global scope. Yikes!There are far better ways to do this in modern languages. For example, use a hash or dictionary construct. A Ruby example:
# Ruby
myhash = { :a => "some text" }
b = "a"
myhash[b.to_sym] # => "some text"
A Python example using a dict: # Python
mydict = { 'a' : "some text" }
b = "a"
mydict[b] # => "some text"
A hash or dictionary gives you the opportunity to give your collection a meaningful name, scopes the evaluation to that object (so you can't arbitrarily retrieve variable data), and provides context. set foo bar
set bar 5
puts [set [set foo]]
OTOH, $$foo does not work in Tcl.Right, we knew about nested variables, but if the derivative of that function doesn't make you lol as you're reading along... well, then, I guess don't vote up.
It's no different from just evaluating any expression, no matter how complex, that returns a string, storing it in a variable then sticking a $ sign in front of it.
This is not a rabbit hole. It's just a bucket someone threw up into and then posted onto reddit.
http://www.quora.com/What-are-PHP-s-main-flaws-(and-good-par...
Amongst other things that PHP gets right is the date/time handling (two functions to go between datetimes and UNIX timestamps, support for timezones).
Here are some PHP frameworks (that handle URL => resource instead of URL => file): http://www.phpframeworks.com/
See: http://paulgraham.com/langdes.html
Let the programmer shoot himself (or herself) in the foot. I do not believe a language's job is to hold a programmer's hand. A programmer will write good code or bad code. A language cannot change that.
Variable variables allow for easy class reflection. I'm curious to hear other uses of variable variables.
PHP, however, is primarily used by either incompetent or inexperienced or deadline-driven people. Under such circumstances you want a language that protects your foot with six layers of hardened steel. If Python was the prevalent language for these groups, I suspect we'd see a lot less security holes and general terribleness. Alas, PHP dominates that market, and people shoot themselves in the foot all the damn time.
To cut a long story short: Give an experienced engineer a powerful, flexible language such as modern PHP, and he will make good use of it. Give a 15-year-old dude in his bedroom the very same language, and hilarity ensues.
public function catalogue($str, &$str2, &$str3) {
depending on whether the parameter is a frequently referenced string, and the type of the parameter altogether. It seems like it's completely trial and error with these sorts of things, and when you note that it takes (iirc) ~70MB to store a million one-char elements in an array, it really matters.Also, sometimes, PHP will patch through returning results of a function, but sometimes, it's actually cheaper to create a temporary, a la
$str = strtolower($foo);
return $str;
These are just a couple of gripes off the top of my head.The thread on reddit, however, indicated that many people were ignorant in regards to viable use cases for variable variables.
I code almost exclusively in Python/Django nowadays but I can honestly think of situations where I wish I had a simple ability to do functions like "$a->$b()" to clean up a piece of code.
Oddly, Rails partials work this way too. They can see the controller's instance variables and are often written without any sort of defined interface, which makes for confusing, brittle code. Fortunately Rails offers the option to pass in :locals (just as php offers the option of simply using functions instead of require).