soledad penadés
repeat 4[fd 100 rt 90]

Archive for the ‘php’ Category

20070716 Serene observations on php4 controversy

Since the PHP group announced they weren't going to support php4 any more when 2007 ends, I have been watching with amusement the reactions this fact has sparked. In general, it feels quite similar to previous public announcements of product discontinuing, such as Windows 98, or Firefox for windows 98, etc.

The most absurd reactions come from very angry people which not only demand support for that product to be extended indefinitely but also do not use the product at all or do not have any decision power about the use of that product in their organisation or environment. They can fill in pages and pages writing infuriating comments about how evil is vendor X for not supporting product Y, and how bad is it for everybody, without giving any solid reason usually.

And the rest of the blame is equally distributed amongst sys admins and developers. Sys admins say they can't upgrade to php5 because the applications running in their systems are not designed with php5 in mind. Developers say they can't develop for php5 because their sys admins do not offer support for php5.

I say stop blaming each other.

It's not that hard to migrate an application to php5, unless it's a complete disaster. For instance, I saw one which had some functions named public and private. Honest! Those functions were repeatedly called thorough the whole code base. Obviously when trying to run this with php5, it failed spectacularly. (Somebody tried to fix it replacing every public with pub and private with priv, and then it broke other parts of the application, but that's another story…)

Personally, I wished every host in Earth had moved to php5. I never use php4 in my projects and it's really annoying to have to downgrade the code for distributing it publicly. It also breaks my heart to have to emulate some php5 functions when working with legacy php4 code for php4-running servers, such as for example array_combine.

And at the end I wonder, can we take seriously a developer or a sys admin which have not learnt about php5 yet, even if it was released more than three years ago? I can't.

20070625 Delicatessen: a wordpress plugin

I just gave the finishing touches to my first public wordpress plugin: Delicatessen. Sounds yummy, doesn't it?

If you're a veeeeeeeery curious person (just like me) you'll love this plug-in. It should satisfy your innermost desires and much more. Well, not that much but at least it will allow you to find who's linking you in del.icio.us, since there's not an easy way of finding that information in del.icio.us itself.

Hope you enjoy it!

20070622 Señales de que tu PHP necesita una refactorización

Dado que a bastante gente le gustó el Signs your php needs refactoring y unas cuantas personas insinuaron la necesidad de una traducción al español, he decidido actuar proactivamente y hacerlo yo misma. Y sin más dilación, sigue el artículo en castellano.

Recientemente, he tenido que trabajar con una aplicación en php que no sólo me ha dado más de un dolor de cabeza, sino que además me ha obligado a hacer uso de toda mi paciencia. Y mientras estaba en ello, pensé Esto es buen material para un artículo, de modo que nadie más haga lo mismo en el futuro, y que nadie más tenga que sufrir lo mismo que he tenido que sufrir yo.

Así que aquí están las señales de que tu PHP necesita una refactorización seria, ya mismo:

Usa variables globales

Esto tiene dos interpretaciones. En primer lugar, tenemos esa forma de programar en la que una serie de variables se pone en el ámbito global, cada función hace un

global $varA, $varB;

etc, y procede entonces a hacer lo que quiera que deba hacer con las variables. Esta es la peor; montones de errores extremadamente difíciles de trazar plagan los programas escritos con esta técnica, más que nada porque las variables globalizadas acaban sobreescribiendo variables que no deberían haber sobreescrito. Es también muy complicado poder hacer un seguimiento de quién está modificando qué, porque no se usan llamadas a funciones para acceder a las variables, sólo declaraciones global. No hay visibilidad en absoluto.

Y luego tenemos la segunda interpretación, en la que las variables que ya son globales de por sí ($_REQUEST, $_POST, $_GET) son usadas (y se abusa de ellas) a lo largo y ancho de toda la aplicación. Te puedes encontrar, por ejemplo, modelos de datos accediendo directamente los arrays $_POST o $_GET, lo cual no sólo introduce complejidad extra en su lógica (por ejemplo: ¿qué ocurre si decidimos enviar los datos con GET en lugar de con POST?) pero además también complican el hacer pruebas unitarias a los diferentes componentes de la aplicación. No puedes simplemente enviar un array de datos a un modelo: ha de ser enviado con POST o GET.

Insisto, esta forma de hacer las cosas proporciona mala visibilidad, ya que no se puede realmente distinguir quién está cambiando qué.

La fiesta de los corchetes

Cada vez que me encuentro cosas como ésta:

$variable['field']['subfield']['subsubfield1'] = 'value1';
$variable['field']['subfield']['subsubfield2'] = 'value2';
$variable['field']['subfield']['subsubfield3'] = 'value3';
$variable['field']['subfield']['subsubfield4'] = 'value4';

… sólo tengo un adjetivo en mente: asqueroso.

Es más fácil y rápido hacer algo tal que esto:

$variable['field']['subfield'] =
  array('subfield1'=>'value1', 'subfield2'=>'value2', 'subfield3'=>'value3', 'subfield4'=>'value4');

Puedes indentarlo con un par de valores por línea, al gusto. La clave está en que si en algún momento necesitas cambiar 'field' o 'subfield', no necesitas hacerlo cuatro veces (incluso si existen cosas como Buscar y Reemplazar). ¡He encontrado casos en los que la Fiesta de los Corchetes ha contaminado veinte e incluso más líneas!

Otro ejemplo de abuso de corchetes se da cuando se recuperan resultados de una base de datos en forma de arrays y son accedidos a saco. Entonces una acaba encontrándose con código como el siguiente para acceder al primer elemento:

$prop1 = $res['results'][0]['property1']
$prop2 = $res['results'][0]['property2']

Más fácil y corto:

list($prop1, $prop2) = array_shift($res['results']);

¿Me podría alguien explicar por qué esa obsesión de la gente con las Fiestas de Corchetes?

Todo es un array

Los objetos se crearon por alguna razón. El hecho de que crear arrays es muy sencillo en php y no tienes que reservar memoria primero y todo eso, al contrario que en otros lenguajes, no quiere decir que debas estructurar todos tus datos con arrays.

El problema de usar arrays como contenedores estructurados de datos es que todo lo que hay dentro es público y no hay forma de usar esas fantásticas funciones set/get que se encargan de impedir que datos incorrectos entren en el array. Por tanto, ¡usa objetos!

Esa es una razón más para pasarte a php5: puedes tener propiedades realmente privadas, de modo que nadie modificará los datos internos de tu clase, tal y como ocurre con los objetos de php4.

Código duplicado

Esto sí que me saca de quicio. Ya no sé ni cuántas veces he leído el código de una aplicación y me he encontrado las mismas tres líneas copiadas y pegadas de función en función y de fichero en fichero. Y me pregunto: ¿les habrán enseñado el concepto de función?

Si hay algo que tiene un aire remotamente familiar a algo que has hecho un poco antes, ¡lo más probable es que esté pidiendo a gritos unos toques de refactorización! Y si necesitas cierta funcionalidad en dos lugares separados, no copies y pegues el código, ¡haz una función!

No sólo el código final acaba siendo más corto, sino que además es más fácil entender cinco líneas de código, que se pueden expandir a cien cuando miras dentro de cada función, que encontrarse de golpe con cien líneas de código y tratar de entender qué está ocurriendo ahí.

El switch interminable

Hablando de bloques de cien líneas, también me he encontrado repetidamente con switch's de trescientas líneas. Y no se lo desearía ni a mi peor enemigo. ¡Es crueldad y explotación mental y debería ser perseguido criminalmente!

Obviamente, los cientos de líneas deberían ser divididos en funciones, de modo que no haga falta usar media hora en un switch para hacerse una idea de qué hace.

Tienes que modificar demasiados ficheros

Si tienes que modificar demasiados ficheros para añadir o modificar incluso la funcionalidad más simple, hay algo que no funciona en tu diseño. Esto suele ocurrir cuando las diferentes partes de la aplicación están demasiado acopladas y cada una necesita saber demasiado acerca de las demás.

Lo peor de esto es que tiende a manifestarse cuando la aplicación se hace grande y está además en modo producción-a-tope, de modo que se piden nuevas funcionalidades constantemente, y la mayoría de programadores acaba mintiéndose a sí mismos: Bueno, no pasa nada por cambiar un par de docenas de ficheros para añadir esta funcionalidad nueva, ya lo simplificaré después. Y todos sabemos perfectamente que ese después nunca llega.

Valores fijos en el código

Las constantes se crearon por alguna razón. Es malo encontrarse cosas tal que

if($result==4) {
// bla
} else if($result==5) {
// bla bla
}

donde determinados valores tienen un cierto significado, pero es aún peor encontrarse cosas como

if($result=='row1') {
// bla
} else if($result=='row2') {
// bla bla
}

ya que por ejemplo, si tecleas algo mal y en lugar de row1 escribes rowl, PHP no se quejará porque es una comparación perfectamente válida. Lo que tú necesitas es usar constantes, de modo que cada vez que intentes usar una constante que no ha sido definida, PHP se queje y tú lo arregles inmediatamente.

Además, aunque parece sencillo distinguir entre "1" (el número uno) y "l" (L minúscula), no es tan sencillo para personas con problemas como dislexia, o simplemente, tú mismo, cuando estés cansado. Y los errores introducidos por culpa de no usar constantes son terriblemente difíciles de localizar; la mayoría de ocasiones hay que pasarse horas yendo línea por línea y tratando de averiguar por qué no funciona. Es mucho más fácil y preventivo definir constantes y dejar de preocuparse de tener que actualizar todos los valores puestos a mano en el código si hace falta cambiarlos luego.

Inconsistencias en la interfaz

Es algo de lo que no se suele hablar mucho, pero creo que es realmente preocupante en PHP. No estoy segura de si es algo inducido por el lenguaje en sí (no hay más que echar un vistazo a las funciones de cadenas), pero hay una extraña tendencia en las aplicaciones php que las lleva a no seguir convención alguna en lo que respecta a argumentos de funciones y tipos de valores devueltos.

A veces las funciones devuelven valores booleanos (true o false) o valores que pueden hacer de booleanos (0 ó 1), otras veces usan valores de retorno al estilo C (0 para éxito y 1 o más para los errores), que son obviamente lo contrario a usar el booleano true para éxito y el booleano false para error, ya que en PHPlandia 0==false y 1==true (a menos que uses los operadores === y !==, más estrictos, pero desafortunadamente ese no es el caso de la mayoría de desarrolladores en php)

En otros casos, las funciones no devuelven nada, pero en cambio usan un array pasado por referencia para escribir resultados en él, algo tal que esto:

function my_function(&$return_array)

Esta práctica es algo que realmente me desagrada, porque a menos que acabes de ver la definición de my_function, es imposible distinguir si

my_function($my_array)

está usando $my_array como un parámetro de entrada o de salida.

Es mejor ponerse de acuerdo en un estilo para devolver valores, y usar ese estilo consistentemente en todas las funciones que escribas. Tal que: siempre devolveremos un objeto con dos propiedades, error que es booleano y representa si la función falló o no, más results que contendrá datos si necesitamos devolver algo.

Con eso, sabes que siempre puedes verificar el valor de $res->error en lugar de tener que verificar primero si existe o no, y entonces ver el valor en sí.

Ya captas la idea…

(Nota: en los comentarios de la versión en inglés se recomienda usar excepciones en lugar de esta solución. Lamentablemente, es sólo aplicable si usas php5)

Conclusión

Algunos de estos problemas prácticamente desaparecerían si tuviéramos un editor de php verdaderamente bueno. Aunque Eclipse cumple su labor decentemente con los plugins para php, la mayor parte del tiempo y debido a la forma en que php funciona, todo queda patas arriba y la funcionalidad de autocompletado es absolutamente inútil porque Eclipse no puede encontrar las clases. Refactorizar es algo que casi depende sólo de tu memoria a corto plazo (creo que ví algo parecido a esto en algún sitio…); otros problemas dependen de si la gente programa estando drogada (recordemos el switch de 300 líneas) o de la competencia en PHP y diseño de software en general.

¡Y ahora es el momento de volver a tu aplicación y mirarla con ojos críticos!

20070605 Signs your PHP needs refactoring

I have had to go through a php application recently which has given me more than one headache and has required me to use all my possible patience. While working with it, I thought This is good material for an article, so that nobody else does the same in the future, and nodody else will need to experience the same displeasure as I have had to.

So here are the signs your PHP application needs a serious refactoring, right now:

Uses global variables

This one has two readings. In the first one, there's that coding style in which a series of variables is placed in the global scope, each function simply does

global $varA, $varB;

etc, and proceeds to do whatever it needs to do with the variables. This one is the worst one; lots of very hard to trace errors plague programs written with this technique, most often because globalized variables end up overwriting variables which they shouldn't, so that's bad. It's also very complicated to keep track of who's modifying what, because there aren't function calls to access the variables, only global statements. There is no visibility at all.

Then there's the second reading, in which readily available global variables ($_REQUEST, $_POST, $_GET) are again used (and abused) throughout the whole application. You can find, for example, data models accessing directly the $_POST or $_GET arrays, which not only introduces extra complexity into their logic (what if we decide to send data with GET instead of POST?, for example) but also complicate unit testing the different pieces of the application. You can't just send an array of data to a model - it has to be in POST or GET.

Again, this way of doing things offers bad visibility, since you can't really tell who's changing what.

Brackets galore

Whenever I find things like this:

$variable['field']['subfield']['subsubfield1'] = 'value1';
$variable['field']['subfield']['subsubfield2'] = 'value2';
$variable['field']['subfield']['subsubfield3'] = 'value3';
$variable['field']['subfield']['subsubfield4'] = 'value4';

… a word comes to my mind: disgusting.

It is way easier and faster to just do something like this:

$variable['field']['subfield'] =
  array('subfield1'=>'value1', 'subfield2'=>'value2', 'subfield3'=>'value3', 'subfield4'=>'value4');

You can indent it having one pair of array values per line, as you wish. The point is that if you ever need to change 'field' or 'subfield', you don't need to do it four times (even if there are things like Search and Replace). I have found cases where the Brackets Galore had contaminated twenty and sometimes even more lines!

Another example of brackets abuse happens when people retrieve results from databases in the form of arrays and access them in the wild. And you end up finding code like this one for accessing the first element:

$prop1 = $res['results'][0]['property1']
$prop2 = $res['results'][0]['property2']

Easier and shorter way:

list($prop1, $prop2) = array_shift($res['results']);

Could somebody explain me what's that obsession of people with Brackets Galores?

Everything's an array

Objects were created for some reason. The fact that creating arrays is very easy with php and you don't have to allocate memory first and all that unlike other languages doesn't mean that you have to structure all your data with arrays.

The problem with using arrays as structured data containers is that everything inside them is public and there's no way of having nice set/get functions which prevent bad data to enter the array. So, use objects!

That is yet another reason for moving to php5: you can have really private properties, so that nobody will modify internal data as it can happen with php4's objects.

Duplicated code

This one really gets on my nerves. How many times have I looked at an application, just to find the same three lines being copied and pasted from function to function and from file to file? And then I wonder: have they ever been taught the concept of function?

If there's something there which looks vaguely similar to something else you did a bit before, it is probably asking for some factorization love! And if you need certain functionality in two separate places, do not copy and paste the same code, make it a function!

Not only the final code ends being shorter, but it is easier to understand five lines of code which can expand to one hundred when you go inside each function, than to get shown one hundred lines of code all of a sudden and try to find out what is going on there.

The neverending switch

Talking about one-hundred-lines blocks, I have also recurrently found three hundred lines switch statements. And believe me, I wouldn't recommend it to my worst enemy. This is cruelty and mental exploitation at its worst and should be criminally punished!

Obviously, the hundreds of lines should be split into functions, so that you don't need to spend half an hour reading a switch to get an idea of what does it do.

You have to modify too many files

If you need to modify lots of files for adding or modifying even a simple feature, something is not working in your design. It usually happens when the different areas in the application are excessively coupled and each one needs to know too much about the other.

The main problem with this is that it tends to manifest itself when the application is getting larger and is also in big production mode, so new features are highly demanded and most of the developers just lie to themselves: It's OK to have to change a few dozen files for adding this new feature, I'll work on simplifying this later. And you know that later never happens.

Hard coded values

Constants were defined for some reason. It is bad to find things like

if($result==4) {
// blah
} else if($result==5) {
// blah blah
}

where numeric values are supposedly meaning something, but it is also quite bad to find things like

if($result=='row1') {
// blah
} else if($result=='row2') {
// blah blah
}

because if for example, you misspell something and instead of row1 you write rowl, PHP is not going to complain at you since it's a perfectly valid comparison. What you need is to use constants, so that whenever you try to use a constant which hasn't been defined, PHP complains and you fix it immediately.

While it looks fairly easy to distinguish between "1" (the number one) and "l" (the lowercase L), it is not that easy for people with problems like dyslexia, or put it simply, when you're tired. And the errors introduced because of not using constants are extremely hard to trace, most of the times you have to spend insane amounts of time going line by line of code and trying to find out why it doesn't work. It's just easier and more preventive to define constants and stop worrying about having to update all the hard coded values in the code later on if needed.

Interface inconsistency

This one doesn't seem to get much attention but it is a really worrying area in PHP. Not sure if it's something inducted by the language itself (just have a look at the string handling functions), but there's an strange tendency in php applications to not to follow standards in what regards to function arguments and return types.

Sometimes functions return boolean values (true or false) or boolean like values (0 or 1), other times they use C style return types (0 for success and 1 or more for errors), which are clearly opposite to using boolean true for success and boolean false for error, since in PHP land 0==false and 1==true (unless you use the stricter === and !== operators, which unfortunately seems to not to be the case for most of the php developers around)

In some other cases, functions do not return anything, but instead use an array passed by reference to write results in it, looking somehow like this:

function my_function(&$return_array)

. I really dislike this practice, because unless you just saw the function definition for my_function, it's impossible to distinguish if

my_function($my_array)

is using $my_array as an input or output parameter.

It is better to agree on a style for return values, and use that style consistently in every function you write. Like: we'll always return an object with two properties, error which is a boolean and represents whether the call failed or not, plus results which will contain data if we need to return something.

With that, you know that you can always check the value of $res->error instead of having to check first if it exists or not, and then check the value itself. You get the idea…

Conclusion

Some of these issues would almost disappear if we had a really good php editor. While Eclipse does a decent job with the php plugins, most of the time, because of the way that php works, everything gets messed up and the autocomplete feature it's useless because it can't find the classes. Refactoring is something that almost relies on your short-term memory only (I think I saw something like this somewhere…), and other issues depend on people being high or not when programming (remember the 300 lines switch) or being competent in PHP and software design in general.

And now is the time to go back to your application and look at it with critical eyes!

20070524 Unexpected T_PAAMAYIM_NEKUDOTAYIM

In almost every programming language, parsing errors tend to be boring, and PHP is not going to be an exception… unless you get one of these:

Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM

If you aren't aware, what it means is "Oh, there's an unexpected double colon where it shouldn't have appeared".

But even if it's a bit obscure, sometimes it's funny to get this error. Just for contrasting with all the plainly boring rest, like unexpected '}', unexpected ',' … all that. Even more funny is that those characters ('::') are also defined as T_DOUBLE_COLON. But why did the programmers decide to use the cryptic error message is something of a mistery for me yet.

The first time I got the error I thought I had found an easter egg! Either that, or the php interpreter had gone nuts…