Libertonia
Portada · Todo · Software Libre · Desarrolladores · Comunidad · Internet · Tecnología · Meta · Diarios
Un vistazo a PHP5 (I)

Programación
Por jcantero
departamento phpvolucionarios , Sección Desarrolladores
Puesto a las Thu Jul 15th, 2004 at 10:23:38 PM CET
La aparición de la versión definitiva de la nueva major revision de PHP es un momento ideal para echar un vistazo --desde el punto de vista del programador-- a las nuevas características que nos presenta este lenguaje, que más que una evolución ha sufrido una revolución.

 


El nuevo PHP5 se apoya en la llamada Zend Engine 2, la nueva versión del motor Zend --desarrollado por Zeev Suraski y Andi Gutmans-- que es el corazón de PHP desde la versión 4. Zend 2 supone un auténtico "cambio de paradigma" en la programación con PHP. Veámoslo.

Command Line Interface

En los ejemplos que presentaré he empleado la versión CLI (Command Line Interface) de PHP5. Os recomiendo usarla si queréis probar vosotros mismos las características de PHP5, ya que prescindiréis de problemas de integración con Apache, etc.

Una rápida manera de conseguir el intérprete CLI es compilar los fuentes con:

    $ ./configure --disable-cgi --enable-cli --without-pear --disable-all
    $ make
El ejecutable aparecerá en el subdirectorio php-5.0.0/sapi/cli/, que podéis copiar a cualquier directorio que queráis usar para las pruebas.

Observaréis que he desactivado todas las extensiones con --disable-all. Es otra manera de no complicarse la vida y obtener una versión con la que juguetear con el intérprete PHP5 sin tener que instalar nada adicional. Pero si quisiérais probar alguna de las nuevas extensiones, tendréis que compilar el CLI convenientemente.

Nota: a pesar de no estar en un entorno web, el intérprete CLI sigue requiriendo que se rodee el código PHP con <?php ... ?> o <? ... ?>.

Objetos y Referencias

En PHP4 las variables que nombran los objetos guardan el objeto completo en sí (sus datos), tal y como hace una variable simple o de array. Esto significa, por ejemplo, que una asignación de objetos del tipo $ob2 = $ob1 realiza en realidad una copia completa, bit a bit, del objeto original en el objeto destino.

Aunque este comportamiento puede parecer deseable a simple vista, acarreaba una serie de problemas consigo. Por ejemplo, si nuestra intención era la de tener no una copia, sino una segunda referencia al mismo objeto, debíamos usar el operador de referencia '&' para indicarlo, de la siguiente manera: $ob2 = & $ob1;.

Pero donde realmente afecta esta decisión de diseño es en el paso de parámetros a una función o método, que en PHP4 se realiza por defecto por valor --al copiarse el argumento actual en el parámetro formal--, también en el caso de objetos. De esta forma, cualquier cambio dentro de la función del objeto en cuestión, se hace sobre la copia del argumento y no sobre el objeto original externo, que ha quedado intacto.

Ello obliga a utilizar el paso de parámetros por referencia en la mayoría de los objetos pasados a funciones y métodos:

    function modifico_un_objeto( & $objeto ) { ... }
El hecho de tener que utilizar explícitamente el operador de referencia '&' de forma continuada provoca la proliferación de errores en PHP4 por "descuidos" y olvidos, errores por lo demás difíciles de detectar y encontrar.

Por este motivo, los diseñadores de PHP5 han realizado un cambio radical en el tratamiento de las variables objeto: en PHP5 todas las variables que nombran objetos son en realidad referencias. No hay que usar el operador '&' ni en las asignaciones, ni en el paso de parámetros que son objetos, ahorrándose con ello un mónton de potenciales errores.

Los que conozcan un lenguaje de programación como Java, no dejarán de observar la "inspiración" de dicha decisión de diseño, y las ventajas que ello comporta al modelo de gestión de la memoria y los objetos. Pero no todo son ventajas. El uso de referencias también trae consigo una serie de cuestiones que el codificador debe tener en cuenta, y que antes no se le planteaban.

Por ejemplo, lo que antes era una sencilla asignación de objetos, ahora se convierte en una asignación de referencias. En PHP5 la expresión $ob2 = $ob1 no realiza ninguna copia del objeto, sino lo que se denomina un alias --ambas variables sirven para manipular el mismo objeto--. Si el programador no lo tiene en cuenta, lo más probable es que termine llevándose más de una sorpresa.

También hay que tener cuidado con que el paso de parámetros objeto a una función o método no produzca efectos colaterales indeseados: si antes en PHP4 un objeto pasado se modificaba dentro del ámbito local de la función, pero no se deseaba que tal cambio se propagara, ahora en PHP5 deberemos utilizar una copia temporal de dicho objeto dentro del cuerpo de la función para que el comportamiento sea idéntico:

    function sin_modificaciones( $objeto ) {
         $temporal = clonar( $objeto )
         manipular( $temporal );
         ...
    }
Todas estas cuestiones problemáticas van a obligar a que PHP5 ofrezca una serie de mecanismos adicionales que ayuden a evitarlas o resolverlas, como el constructor de copia. Mecanismos ya presentes en otros lenguajes orientados a objetos, y que veremos más adelante.

No obstante, el lector no debería llevarse la impresión de que el uso de referencias es "problemático". Una expresión como la siguiente:

    $ob1->getOb2()->getOb3()->metodo();
es perfectamente válida en PHP5 y se comporta como se espera --invocando metodo(), y posiblemente cambiando el estado del objeto devuelto por getOb3()--, mientras que la misma semántica en PHP4 requiere de la utilización de dos asignaciones de variables temporales de referencia:
    $ob2 = & $ob1->getOb2();
    $ob3 = & $ob2->getOb3();
    $ob3->metodo();
algo realmente engorroso a medida que se anidan las llamadas.

Clases

La principal novedad en las clases de PHP5 es la inclusión de modificadores de control de acceso para implementar la encapsulación --piedra angular en la programación orientada a objetos de la que adolecía PHP4--.

PHP5 introduce tres palabras clave (public, private y protected) que sustituyen a var en la definición de variables miembro --atributos-- de la clase, y que preceden a la definición de funciones miembro --métodos--:

    class Clase {
        private $atributo; 
        public metodo( $x, $y ) { ... }
    }
Los tres modificadores tienen el significado "natural" esperado por cualquier programador que provenga de otros lenguajes OO:
  • public: la variable o función es accesible desde cualquier ámbito --la misma clase, otra clase o el ámbito global--.
  • private: la variable o función sólo es accesible desde dentro de la clase a la que pertenece --métodos de dicha clase--.
  • protected: la variable o función sólo es accesible desde dentro de la clase a la que pertenece o de cualquiera de sus clases derivadas.

En PHP4 todas las variables y las funciones son públicas. Por compatibilidad, PHP5 considera públicas todas las funciones a las que explícitamente no se les proporcione un modificador de acceso de los tres anteriores. PHP5 también admite por compatibilidad el uso de var como sinónimo de public, pero su uso está desaconsejado (se considera 'deprecated').

El control de acceso es un mecanismo necesario para poder limitar el estado que puede tener un objeto, representado por el valor de su variables. Lo habitual es declarar éstas privadas y acceder a las mismas mediante métodos proporcionados a tal efecto: los getters o accesores y los setters o mutadores:

<?php
     class Clase {
         private $propiedad;
 
         function getPropiedad() {
             return $this->propiedad;
        }
        function setPropiedad( $val ) {
            $this->propiedad = $val;
        }
    }

    $ob = new Clase;
    $ob->setPropiedad( "Un valor" );
    print( $ob->getPropiedad() );
?>
Estas variables privadas y accesibles mediante getter/setter suelen denominarse habitualmente propiedades. PHP5 lleva más allá el control de las propiedades mediante dos métodos especiales: __get() y __set(). El intérprete de PHP los invoca (si se han implementado en la clase) si se intenta leer (__get) o escribir (__set) en una variable de la clase que no existe:
<?php
     class Clase {
         public $a;
         protected $b;
         private $c;
         function __set( $name, $val ) {
             print("Intentando escribir en la propiedad $name el valor $val\n");
         }
         function __get( $name ) {
             print("Intentando acceder a la propiedad $name\n");
         }
         function test() {
             print( "------------- dentro de la clase ---------------\n" );
             $this->a = 4;   // atributos que existen
            $this->b = 5;
            $this->c = 6;
            $this->x = 7;   // atributo que no existe
            print( "------------------------------------------------\n" );
        }
    }
    
    $ob = new Clase();
    
    $ob->a = 1;         // atributo que existe
    print( $ob->z );    // atributos que no existen (acceso y escritura)
    $ob->y = 2;     
    //$ob->b = 3;       // intentar acceder a un atributo privado produce error
    $ob->test();        // probar desde dentro de la clase
?>
Como se puede observar, __get() y __set() sólo funcionan con variables no declaradas en la clase. Si están declaradas, no se les invoca. En el caso de ser privadas, se produce un error de acceso.

En el ejemplo anterior hemos empleado esta característica para realizar un primitivo control de errores, pero con ella podríamos por ejemplo crear y destruir dinámicamente propiedades a nuestro antojo --guardándolas en un array--.

(Nota: PHP reserva todos los identificadores que comienzan por "__" para su uso interno. Nunca deberían nombrarse métodos de nuestras clases con nombres de tal estilo, o podrían colisionar con nombres utilizados por el propio intérprete, produciéndose errores o resultados inesperados).

Sobrecarga de métodos (Overloading)

La sobrecarga de funciones es otra de las características habituales en lenguajes OO de la que carece PHP4. Los habilidosos programadores de PHP4 lidiaban con esta carencia utilizando diversas técnicas, como el empleo de parámetros opcionales:

    class Clase {
        ...
        function sobrecargada( $x, $y = 0, $z= "" ) { ... }
    }
    $ob = new Clase;
    $ob->sobrecargada( 1, 2, "hola" );
    $ob->sobrecargada( 1 );
    $ob->sobrecargada( 1, 2 );
Esta técnica está limitada por las posibilidades de posicionamiento de parámetros opcionales, pero otra manera más completa es utilizar las funciones que proporciona PHP para la gestión de parámetros --func_get_args(), func_num _args() y func_get_arg()--:
<?php
     class Clase {
         public function sobrecargado() {
             $args = func_get_args();
             if ( 1 == func_num_args() ) {
                 if ( is_int( $args[0] ) )
                      $this->sobrecargado_int( $args[0] );
                if ( is_string( $args[0] ) )
                     $this->sobrecargado_string( $args[0] );
            }
            else if ( 2 == func_num_args() ) {
                if ( is_int( $args[0] ) && is_string( $args[1] ) )
                     $this->sobrecargado_int_string( $args[0], $args[1] );
            }
        }
        private function sobrecargado_int( $i ) {
            print( "sobrecargado_int = $i\n" );
        }
        private function sobrecargado_string( $s ) {
            print( "sobrecargado_string: $s\n" );
        }
        private function sobrecargado_int_string( $i, $s ) {
            print( "sobrecargado_int_string: $i, $s\n" );
        }
    }

    $ob = new Clase();
    $ob->sobrecargado( 1 );
    $ob->sobrecargado( "hola" );
    $ob->sobrecargado( 2, "mundo" );
?>
La mala noticia es que tampoco PHP5 soporta sobrecarga de métodos. Sin embargo, los programadores de PHP5 tienen la vida un poco más fácil porque Zend 2 ha añadido un soporte equivalente al que __get() y __set() permiten con las variables, pero para los métodos. El método __call() --si existe-- es invocado para todo método que no exista en la clase actual. Ello nos permite utilizarlo como una función catch-all desde la que controlar todas las funciones que queramos sobrecargar, agrupando todo el código de gestión de la "sobrecarga" en un único punto:
<?php
     class Clase {
         function otra( $x ) {
             print( "dentro de otra(): $x\n" );
         }
         private function privada( $x ) {
             print( "dentro de privada(): $x\n" );
         }
         function __call( $name, $args ) {
             // metodo 'sobrecargado'
             if ( $name == 'sobrecargado' ) {
                 if ( 1 == count($args) ) {
                     if ( is_int( $args[0] ) )
                         $this->sobrecargado_int( $args[0] );
    
                    if ( is_string( $args[0] ) )
                        $this->sobrecargado_string( $args[0] );
                }
                else if ( 2 == count($args) ) {
                    if ( is_int( $args[0] ) && is_string( $args[1] ) )
                        $this->sobrecargado_int_string( $args[0], $args[1] );
                }
            }
            else if ( $name == 'privada' ) {
                $this->privada( 93 );
            }
        }
        private function sobrecargado_int( $i ) {
            print( "sobrecargado_int = $i\n" );
        }
        private function sobrecargado_string( $s ) {
            print( "sobrecargado_string: $s\n" );
        }
        private function sobrecargado_int_string( $i, $s ) {
            print( "sobrecargado_int_string: $i, $s\n" );
        }
    }

    $ob = new Clase();
    $ob->sobrecargado( 1 );
    $ob->sobrecargado( "hola" );
    $ob->otra( 56 );    // existe, no capturada por __call
    $ob->sobrecargado( 2, "mundo" );
    $ob->privada();     // existe, no capturada por __call (error)
?>
También en el caso de __call() sólo se llama cuando un método no ha sido definido. Si se ha definido, se llama al método normalmente sin invocar a _call() (y si es privado, el control de acceso producirá el error que debería dar).

La mejora no es demasiado significativa, pero tal vez podrían encontrarse otros usos más creativos (además del obvio de control de errores de llamadas a métodos inexistentes).

Constructores y destructores

En PHP4, el constructor de un objeto se denotaba con el mismo nombre que la clase, tal y como se hace en muchos lenguajes de programación orientados a objetos. Sin embargo, a diferencia de éstos, los constructores en PHP4 se heredan, creando una serie de inconvenientes que analizaremos más adelante.

Para evitar estas situaciones, en PHP5 se ha escogido que el constructor tenga un nombre homogéneo en todas las clases: __construct(). Por compatibilidad hacia atrás, si dicho método __construct() no existe, se seguirá la misma regla que en PHP4 --se buscará un método con el mismo nombre que la clase--; y si tampoco se encuentra, se proporcionará un constructor por defecto que simplemente reservará el espacio en memoria para el objeto creado con new.

Un detalle que conviene remarcar es que, al no existir la sobrecarga de métodos, tampoco puede sobrecargarse el constructor. El constructor es único, y si necesitaramos distintas versiones, deberíamos proceder aplicando alguna de las técnicas ya comentadas en el apartado de sobrecarga de métodos.

Por otro lado, PHP5 también soporta el concepto de destructor, implementado --si se desea-- mediante el identificador __destruct(). Este destructor funciona así: cuando un objeto ha quedado inaccesible, al llegar la cuenta de referencias a cero, el destructor se invoca antes de liberar la memoria definitivamente.

No sé hasta que punto se puede hablar de garbage recollector en PHP, comparado con los complejos mecanismos de recogida de basura implementados en la máquina virtual de Java o .NET, pero por hacer una (siempre peligrosa) analogía, el mecanismo de destructor de PHP5 está más próximo a C#, donde existe destructor, que se invoca siempre antes que el GC libere el objeto, que a C++ --sin GC, liberación de memoria explícita-- o Java --sin destructor, finalize() no está garantizada su ejecución--.

<?php
     class Clase {
         private $val;
         function __construct( $val ) {
             printf( "Invocando al constructor... ($val)\n" );
             $this->val = $val;
        }
        function show() {
            printf( "Valor de val=$this->val\n" );
        }
        function __destruct() {
            printf( "Invocando al destructor...($this->val)\n" );
        }
    }

    function test( $i ) {
        $ob = new Clase( $i );
        $ob->show();
    } // se acaba el ambito

    for( $i=0; $i<100; $i++ ) {
         test( $i );
     }
 ?>
En el ejemplo anterior podemos ver como los objetos no son "recolectados" por el GC cuando se necesita memoria, sino que son destruidos directamente al salir del ámbito.

Clonado. Constructor copia

Para resolver el problema del aliasing, PHP5 ofrece un mecanismo de constructor de copia: cuando queremos copiar un objeto, utilizaremos una nueva palabra clave del lenguaje clone.

    $ob2 = clone $ob1;
El efecto de clone es realizar una copia completa, bit a bit, del objeto origen ($ob1) en el objeto destino ($ob2). Es el mismo comportamiento que teníamos en la copia de objetos de PHP4.

Sin embargo, este operador no es suficiente. Otra de las consecuencias de usar referencias a objetos es que, si un objeto tiene a su vez variables que son objetos, esta copia será superficial (shallow copy), y en realidad ambos objetos estarán apuntando a la misma instancia del objeto contenido.

Para poder realizar una copia en profundidad (deep copy) o, en general, controlar el proceso de copia --clonado-- de un objeto, podemos redefinir en cualquier clase el método especial __clone(). Este método se invoca después de copiar todos los atributos del objeto, de forma que sólo nos tendremos que preocupar de aquellos atributos en los cuales la simple copia no nos sirva:

<?php
     class Clase {
         private $val;
         function __construct( $val ) {
             $this->val = $val;
        }
        function getValor() {
            return $this->val;
        }
        function setValor( $val ) {
            $this->val = $val;
        }
    }
    class ClaseCompuesta {
        private $val;
        private $ob;
        function __construct( $val, $ob ) {
            $this->val = $val;
            $this->ob = new Clase( $ob );
        }
        function getValor() {
            return $this->val;
        }
        function setValor( $val ) {
            $this->val = $val;
        }
        function getObjeto() {
            return $this->ob->getValor();
        }
        function setObjeto( $val ) {
            $this->ob->setValor( $val );
        }
        function __clone() {
            // copia en profundidad
            $this->ob = new Clase( $this->getObjeto() );
        }
    }

    $ob = new ClaseCompuesta( 1, 1 );
    $clon = clone $ob;
    printf( "ob:   val=". $ob->getValor() ." ob=". $ob->getObjeto() ."\n");
    printf( "clon: val=". $clon->getValor() ." ob=". $clon->getObjeto() ."\n");
    printf( "Cambiando clon...\n" );
    $clon->setValor( 2 );
    $clon->setObjeto( 3 );
    printf( "ob:   val=". $ob->getValor() ." ob=". $ob->getObjeto() ."\n");
    printf( "clon: val=". $clon->getValor() ." ob=". $clon->getObjeto() ."\n");
?>
En este ejemplo, si comentáis la función __clone(), podréis observar el comportamiento de la copia superficial.

Una advertencia importante respecto al clonado. Esta operación ha ido variando a lo largo del desarrollo de PHP5, y es posible que encuentre documentación que difiera de los expuesto aquí: desde llamadas directas a __clone() hasta el uso de un segundo parámetro implícito ($that).

Ninguna de ellas funciona en la versión definitiva de PHP5. Si desea clonar un objeto, debe emplear clone, no llamar al método __clone(). En cuanto a recuperar valores del objeto original, el objeto $this tiene dichos valores copiados, y no se requiere el uso de ningún otro objeto implícito.

<hr> En la segunda parte seguiremos profundizando en las novedades de PHP5, echando un vistazo a los miembros de clase, a la herencia, clases abstractas e interfaces, excepciones y otras novedades del entorno PHP5.

< Galopín, software libre de facturación (2 comments) | Lenguajes de Desarrollo Libre y Puestos de Trabajo (14 comments) >
Enlaces Relacionados
· PHP
· PHP5
· Zend Engine 2
· More on Programación
· Also by jcantero

Menu
· crear cuenta
· FAQ
· búsqueda
· Fuentes de Noticias

Login
Nueva cuenta
Usuario:
Contraseña:

Ver: Modo: Orden:
Un vistazo a PHP5 (I) | 8 comentarios (8 temáticos, editoriales, 0 ocultos)
Y digo yo... (none / 0) (#1)
por davinci (davinci at ecol org) a las Fri Jul 16th, 2004 at 10:12:45 AM CET
(Información Usuario)

<modo mundo_ideal on>

¿Para qué existirán tantos lenguajes, con toda la parafernalia, incompatibilidades y "guerras santas" que ello conlleva, si al final todos (o muchos de ellos al menos) van tendiendo a lo mismo?

Lo digo porque, tras leer tu desglose de la nueva versión de PHP, no puedo dejar de pensar en lo mucho que se va pareciendo el lenguaje a otros como Ruby o Python.

Quiza algún día puedan todos compartir "tripas" y los distintos sabores sean el equivalente de una pegatina chula en la gorra ;)

<modo mundo_ideal off>


¡Es la guerrrrrrra!


Azúcar sintáctico (none / 0) (#3)
por jcantero (jcantero@agujero-negro.escomposlinux.org) a las Fri Jul 16th, 2004 at 06:06:45 PM CET
(Información Usuario) http://www.escomposlinux.org/jcantero/

A las meras diferencias sintácticas los expertos en lenguajes de programación lo denominan así: "azúcar sintáctico".

En este caso, creo que todos los lenguajes que yo llamaría "OO de segunda generación" tienen la misma inspiración: Java (que a su vez está fuertemente inspirado en Smalltalk, pero eso es otro cantar).

Python y Ruby de momento no te puedo decir, porque no los he mirado. Pero en el caso de C# y PHP5 es clamoroso. Lo cual no quiere decir que esté mal. Simplemente, que los que conozcan uno de ellos, que sepan que el paso a uno de los otros es sencillo (al menos a nivel de sintáxis y semántica básica del lenguaje).

--
"Papá, ¡Internet es más que una red pornográfica global!" -- Lisa Simpson
[ Padre ]


 
Los lenguajes *parecen* equivalentes... (none / 0) (#8)
por pnongrata (libertonia.5.pnongrata@spamgourmet.com) a las Mon Jul 19th, 2004 at 03:36:34 PM CET
(Información Usuario)

Pero no lo son. Paul Graham dice esto en su ensayo If LISP is so great:
Indeed, if programming languages were all more or less equivalent, there would be little justification for using any but the most popular. But they aren't all equivalent, not by a long shot.

Recomiendo encarecidamente leer el artículo enlazado en la cita.
--
jabber:pnongrata@jabber.sk
[ Padre ]


 
Al fin una orientación a objetos decente (none / 0) (#2)
por osoh (imobachgs at softhome dot net) a las Fri Jul 16th, 2004 at 10:14:26 AM CET
(Información Usuario) http://www.banot.net/~imo/

Bueno, sin ánimo de ofender (y aunque trabajo bastante con PHP), creo que es justo reconocer que en las versiones anteriores la orientación a objetos de PHP era, cuanto menos, pobre. Ahora parece que el tema ha mejorado sensiblemente, tal y como Javi nos muestra en el artículo.

Por cierto Javi, gran trabajo ;-)

Saludos.
--
Que no haya pasión que no valga el mal que cien años dura (Enrique Bunbury)


Pues espera (none / 0) (#4)
por jcantero (jcantero@agujero-negro.escomposlinux.org) a las Fri Jul 16th, 2004 at 06:13:37 PM CET
(Información Usuario) http://www.escomposlinux.org/jcantero/

Que todavía falta todo el tema de la herencia, etc. =)

De todas formas, pienso ser crítico con algunos asuntos. Bueno, ya lo leeréis (y opinaréis, espero).

> Por cierto Javi, gran trabajo ;-)

Gracias. O:-)

P.D.: Por cierto, una pregunta: ¿Alguien está trabajando ya con PHP5?

--
"Papá, ¡Internet es más que una red pornográfica global!" -- Lisa Simpson
[ Padre ]


 
Why PHP 5 Rocks! (none / 0) (#5)
por advocatux a las Fri Jul 16th, 2004 at 06:48:33 PM CET
(Información Usuario)

Por si os interesa, en OnLAMP (O'Reilly) hay un artículo de Adam Trachtenberg, autor de "Upgrading to PHP 5", titulado "Why PHP 5 Rocks!"
--
- Por una Europa libre de Patentes de Software - EuropeSwPatentFree


Y también (none / 0) (#6)
por jcantero (jcantero@agujero-negro.escomposlinux.org) a las Sat Jul 17th, 2004 at 08:38:37 AM CET
(Información Usuario) http://www.escomposlinux.org/jcantero/

Tienen un excerpt (¿extracto?) del mismo: el capítulo 4 SQLite.

--
"Papá, ¡Internet es más que una red pornográfica global!" -- Lisa Simpson
[ Padre ]


(idem) (none / 0) (#7)
por jcantero (jcantero@agujero-negro.escomposlinux.org) a las Sun Jul 18th, 2004 at 10:11:00 AM CET
(Información Usuario) http://www.escomposlinux.org/jcantero/

Ah, y el mismo autor también tiene en OnLAMP otro artículo sobre SimpleXML, una de las novedades de PHP5.

--
"Papá, ¡Internet es más que una red pornográfica global!" -- Lisa Simpson
[ Padre ]


 
Un vistazo a PHP5 (I) | 8 comentarios (8 temáticos, editoriales, 0 ocultos)
Ver: Modo: Orden:

ecol Logo Powered by Scoop
Todas las Marcas Registradas y copyrights de esta página son propiedad de sus respectivos dueños.
Los comentarios son propiedad del que los escribe.
Los iconos de las noticias y el logotipo son propiedad de Javier Malonda.
El Resto © 2002 Escomposlinux.org y aledaños.

Puedes sindicar los contenidos de libertonia en formato RSS 1.0 y RDF 0.9. También se puede sindicar la cola de envíos pendientes de moderación.

El proyecto escomposlinux.org está dedicado a la memoria de tas

crear cuenta | faq | búsqueda