Hi,

can you please enable this SVN account?

Please find the file attached he translated.

Thank You!

Yago

On Sat, Mar 27, 2010 at 12:19 PM, Leonel Duran Fuentes <
project25...@gmail.com> wrote:

>  I would like to have an SVN account to help with the Spanish translation
> of the PHP Manual.
>
> The current lead for the Spanish translation group 'yago' has suggested me
> to apply for a SVN account to keep helping.
>
> Thanks a lot.
>



-- 
Yago Ferrer
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision: 288721 $ -->
<!-- EN-Revision: 288721 Maintainer: Leonel Status: pending -->
 <appendix xml:id="oop4" xmlns="http://docbook.org/ns/docbook"; xmlns:xlink="http://www.w3.org/1999/xlink";>
  <title>Clases y Objetos (PHP 4)</title>

  <sect1 xml:id="keyword.class">
   <title><literal>class</literal></title>
   <para>
    Una clase es una colección de variables y funciones que trabajan con
    estas variables. Las variables se definen utilizando <literal>var</literal> y
    las funciones utilizando <literal>function</literal>. Una clase se define empleando la
    siguiente sintáxis:    
   </para>
   <para>
    <informalexample>
     <programlisting role="php">
<![CDATA[
<?php
class Cart {
    var $items;  // Objetos en nuestro carrito de compras

    // Agregar $num artículos de $artnr al carrito

    function add_item($artnr, $num) {
        $this->items[$artnr] += $num;
    }

    // Sacar $num artículos de $artnr fuera del carrito

    function remove_item($artnr, $num) {
        if ($this->items[$artnr] > $num) {
            $this->items[$artnr] -= $num;
            return true;
        } elseif ($this->items[$artnr] == $num) {
            unset($this->items[$artnr]);
            return true;
        } else {
            return false;
        }
    }
}
?>
]]>
     </programlisting>
    </informalexample>
   </para>
 
   <para>
    Esto define una clase llamada Cart que consiste de una matriz asociativa
    de artículos en el carrito y dos funciones para agregar y quitar
    elementos de este carrito.    
   </para>

   <warning>
    <simpara>
     <emphasis>NO</emphasis> se puede separar una definición de clase en
     múltiples ficheros. <emphasis>Tampoco</emphasis> es posible separar una 
     definición de clase en múltiples bloques PHP, a menos que la división sea dentro
     de una declaración de método. Lo siguiente no funcionará:     
    </simpara>
    <para>
     <informalexample>
      <programlisting role="php">
<![CDATA[
<?php
class test {
?>
<?php
    function test() {
        print 'OK';
    }
}
?>
]]>
      </programlisting>
     </informalexample>
    </para>
    <simpara>
     Sin embargo, lo siguiente es permitido:
    </simpara>
    <para>
     <informalexample>
      <programlisting role="php">
<![CDATA[
<?php
class test {
    function test() {
        ?>
        <?php
        print 'OK';
    }
}
?>
]]>
      </programlisting>
     </informalexample>
    </para>
   </warning>

   <simpara>
    Las siguientes notas de precaución son válidas para PHP 4.
   </simpara>
    
   <caution>
    <simpara>
     El nombre <literal>stdClass</literal> es usado internamente por
     Zend y está reservado. No es posible tener una clase llamada
     <literal>stdClass</literal> en PHP.
    </simpara>
   </caution>
    
   <caution>
    <simpara>
      Los nombres de función <literal>__sleep</literal> y
      <literal>__wakeup</literal> son mágicos en las clases de PHP. No
      se puede tener funciones con estos nombres en ninguna
      clase a menos que se desee la funcionalidad mágica asociada
      con ellas. Ver abajo para más información.
    </simpara>
   </caution>
    
   <caution>
    <simpara>
      PHP reserva todos los nombres de función que empiezan con <literal>__</literal> como mágicos.
      Se recomienda que no se utilicen nombres de función con
      <literal>__</literal> en PHP a menos que se quiera alguna funcionalidad mágica que esté documentada.
    </simpara>
   </caution>

   <simpara>
    En PHP 4, para variables <literal>var</literal> solamente se permiten inicializadores constantes.
    Para inicializar variables con valores no constantes,
    se requiere una función de inicialización que es invocada automáticamente
    cuando un objeto se está construyendo a partir de la clase.
    Tal función es llamada un constructor (ver más abajo).
   </simpara>
   <informalexample>
    <programlisting role="php">
<![CDATA[
<?php
class Cart {
    /* Ninguno de estos funcionará en PHP 4. */
    var $todays_date = date("Y-m-d");
    var $name = $firstname;
    var $owner = 'Fred ' . 'Jones';
    /* Pero matrices que contengan valores constantes, si lo harán. */
    var $items = array("VCR", "TV");
}

/* Esta es la manera en que debería hacerse. */
class Cart {
    var $todays_date;
    var $name;
    var $owner;
    var $items = array("VCR", "TV");

    function Cart() {
        $this->todays_date = date("Y-m-d");
        $this->name = $GLOBALS['firstname'];
        /* etc. . . */
    }
}
?>
]]>
    </programlisting>
   </informalexample>

   <para>
    Las clases son tipos, es decir, son planos para las variables
    de verdad. Se tiene que crear una variable del tipo deseado con el
    operador <literal>new</literal>.
   </para>
 
   <informalexample>
    <programlisting role="php">
<![CDATA[
<?php
$cart = new Cart;
$cart->add_item("10", 1);

$another_cart = new Cart;
$another_cart->add_item("0815", 3);
?>
]]>
    </programlisting>
   </informalexample>
 
   <para>
    Esto crea los objetos <varname>$cart</varname> y
    <varname>$another_cart</varname>, ambos de la clase Cart. La función
    <literal>add_idem()</literal> del objeto <varname>$cart</varname> es invocada para agregar 1
    elemento del artículo 10 a <varname>$cart</varname>. 3 elementos del
    artículo número 0815 son agregados a <varname>$another_cart</varname>.
   </para>
   
   <para>
    Ambos, <varname>$cart</varname> y <varname>$another_cart</varname>, tienen
    las funciones <literal>add_item()</literal>, <literal>remove_item()</literal>
    y una variable <varname>items</varname>. Estas son funciones y variables distintas. Se puede
    pensar en los objetos como algo semejante a directorios en un sistema de ficheros.
    En un sistema de ficheros se pueden tener dos diferentes ficheros llamados
    <filename>README.TXT</filename>, siempre y cuando éstos, estén en directorios distintos.
    Tal como con los directorios donde se tiene que teclear la trayectoria de nombre completa para
    poder alcanzar cada fichero desde el directorio de nivel máximo, se tiene que especificar
    el nombre completo de la función que se desea invocar: en términos de PHP, el directorio de
    nivel máximo sería el espacio de nombres global, y el separador en las trayectorias de nombre
    sería <literal>-&gt;</literal>.  Así, los nombres
    <varname>$cart-&gt;items</varname> y
    <varname>$another_cart-&gt;items</varname> nombran a dos variables distintas.
    Nótese que la variable se llama <varname>$cart-&gt;items</varname>, y no
    <varname>$cart-&gt;$items</varname>, es decir, un nombre de variable en PHP tiene
    únicamente un sólo signo de dólar (<literal>$</literal>).
   </para>

   <informalexample>
    <programlisting role="php">
<![CDATA[
<?php
// correcto, solamente un $
$cart->items = array("10" => 1);

// inválido, porque $cart->$items se vuelve $cart->""
$cart->$items = array("10" => 1);

// correcto, pero podría ser o no lo que se pretendía:
// $cart->$myvar se vuelve $cart->items
$myvar = 'items';
$cart->$myvar = array("10" => 1);  
?>
]]>
    </programlisting>
   </informalexample>

   <para>
    Dentro de una definición de clase, no se conoce bajo que nombre el objeto será
    accesible dentro del programa: al momento en que la clase Cart fue
    escrita, se desconocía si el objeto sería nombrado
    <varname>$cart</varname>, <varname>$another_cart</varname>, o algo
    distinto posteriormente. Siendo así,
    no se puede escribir <varname>$cart-&gt;items</varname> dentro de la clase Cart
    propiamente. En cambio, para ser capáz de acceder a sus propias funciones y 
    variables desde el interior de una clase, es posible utilizar la pseudovariable
    <varname>$this</varname> que puede ser leída como 'lo mío' u 'objeto
    actual'. Así, '<varname>$this-&gt;items[$artnr]</varname> +=
    <varname>$num</varname>' puede leerse como 'agregar <varname>$num</varname> al
    contador <varname>$artnr</varname> de mi propia matriz de artículos' o 'agregar
    <varname>$num</varname> al contador <varname>$artnr</varname> de la matriz de
    artículos dentro del objeto actual'.
   </para>

   <note>
    <para>
     La pseudovariable <varname>$this</varname> normalmente no está definida si
     el método en el que se encuentra alojada es invocado de manera estática. Pero, 
     ésta, no es una regla estricta: <varname>$this</varname> está definida si un método es
     invocado estáticamente desde el interior de otro objeto. En este caso, el valor de
     <varname>$this</varname> será aquel del objeto que realiza la invocación. Esto se
     ilustra en el siguiente ejemplo:
     <informalexample>
      <programlisting role="php">
<![CDATA[
<?php
class A
{
    function foo()
    {
        if (isset($this)) {
            echo '$this is defined (';
            echo get_class($this);
            echo ")\n";
        } else {
            echo "\$this is not defined.\n";
        }
    }
}

class B
{
    function bar()
    {
        A::foo();
    }
}

$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
]]>     
      </programlisting>
      &example.outputs;
      <screen>
<![CDATA[
$this is defined (a)
$this is not defined.
$this is defined (b)
$this is not defined.
]]>
      </screen>
     </informalexample>
    </para>
   </note>

   <note>
    <para>
    Existen algunas funciones apropiadas para manejar clases y objetos. Quizas se quiera
    echar un vistazo al las <link linkend="ref.classobj">Funciones 
    Class/Object</link>.
    </para>
   </note>
  </sect1>
  
  <sect1 xml:id="keyword.extends">
   <title><literal>extends</literal></title>

   <para>
    Frecuentemente son necesarias clases con variables y funciones semejantes
    a los de otra clase ya existente. De hecho, es una buena práctica
    definir una clase genérica que pueda ser utilizada en todos sus
    proyectos y adapatar esta clase a las necesidades de cada uno de sus
    proyectos específicos. Para facilitar esto, las clases pueden ser
    extensiones de otras clases. La clase extendida o derivada
    tiene todas las variables y funciones de la clase base (esto es
    llamado 'herencia' a pesar del hecho de que nadie ha muerto) y aquello que
    se agregue en la definición extendida. No es posible
    disminuir una clase, es decir, remover la definición de cualquier función o
    variable existente. Una clase extendida siempre es dependiente de 
    una sóla clase base, es decir, la herencia múltiple no 
    está soportada. Las clases son extendidas utilizando la palabra clave '<literal>extends</literal>'.
   </para>
 
   <informalexample>
    <programlisting role="php">
<![CDATA[
<?php
class Named_Cart extends Cart {
    var $owner;
  
    function set_owner ($name) {
        $this->owner = $name;
    }
}
?>
]]>
    </programlisting>
   </informalexample>
 
   <para>
    Esto define una clase llamada Named_Cart que contiene todas las variables y funciones de
    Cart más una variable adicional <varname>$owner</varname> y una
    función adicional <literal>set_owner()</literal>. Se crea un carrito con nombre de la manera habitual y
    ahora se puede indicar y obtener el dueño del carrito. Aún se pueden utilizar las funciones de
    carrito normal en los carritos con nombre:
   </para>
 
   <informalexample>
    <programlisting role="php">
<![CDATA[
<?php
$ncart = new Named_Cart;    // Crear un carrito con nombre
$ncart->set_owner("kris");  // Nombrar el carrito
print $ncart->owner;        // imprimir el nombre del dueño del carrito
$ncart->add_item("10", 1);  // (funcionalidad heredada de cart)
?>
]]>
    </programlisting>
   </informalexample>

   <para>
    Esto también es llamado una relación "padre-hijo". Se crea una clase,
    el padre, y se utiliza <literal>extends</literal> para crear una nueva clase
    <emphasis>basada</emphasis> en la clase padre: la clase hijo. Es posible
    incluso utilizar esta nueva clase hijo y crear otra clase basada en esta clase
     hijo.
   </para>
   <note>
    <para>
     ¡Las clases deben de estar definidas antes de ser utilizadas! Si se desea que la clase
     <literal>Named_Cart</literal> extienda a la clase
     <literal>Cart</literal>, se tendrá que definir primero la clase
     <literal>Cart</literal>. Si se quiere crear otra clase llamada
     <literal>Yellow_named_cart</literal> basada en la clase
     <literal>Named_Cart</literal> se tiene que definir primero
     <literal>Named_Cart</literal>. Para resumir: el orden en que las
     clases se definen es importante.
    </para>
   </note>
  </sect1>

  <sect1 xml:id="oop4.constructor">
   <title>Constructores</title>

   <para>
    Los constructores son funciones en una clase que son invocadas
    automáticamente cuando se crea una nueva instancia de una clase con
    <literal>new</literal>. Una función se vuelve un constructor, cuando
    tiene el mismo nombre que la clase. Si una clase
    no tiene constructor, el constructor de la clase base será
    invocado, si es que existe.
   </para>
 
   <informalexample>
    <programlisting role="php">
<![CDATA[
<?php
class Auto_Cart extends Cart {
    function Auto_Cart() {
        $this->add_item("10", 1);
    }
}
?>
]]>
    </programlisting>
   </informalexample>
 
   <para>
    Esto define una clase Auto_Cart que es una Cart más un constructor
    que inicializa el carrito con un elemento del artículo número "10"
    en cada ocasión que un nuevo Auto_Cart es creado con "<literal>new</literal>".
    Los constructores pueden llevar argumentos y estos argumentos pueden ser opcionales, lo que
    los hace mucho más útiles. Para poder seguir utilizando la clase
    sin parámetros, todos los parámetros para los constructores deben hacerse
    opcionales proporcionando los valores por omisión.
   </para>
 
   <informalexample>
    <programlisting role="php">
<![CDATA[
<?php
class Constructor_Cart extends Cart {
    function Constructor_Cart($item = "10", $num = 1) {
        $this->add_item ($item, $num);
    }
}
 
// Comprar las mismas cosas aburridas de siempre.
$default_cart = new Constructor_Cart;
 
// Comprar en serio...
$different_cart = new Constructor_Cart("20", 17);
?>
]]>
    </programlisting>
   </informalexample>

   <para>
    También se puede utilizar el operador <literal>@</literal> para
    <emphasis>callar</emphasis> los errores que ocurren en el constructor, para ejemplo
    <literal>@new</literal>.
   </para>

   <informalexample>
    <programlisting role="php">
<![CDATA[
<?php
class A
{
    function A()
    {
        echo "I am the constructor of A.<br />\n";
    }

    function B()
    {
        echo "I am a regular function named B in class A.<br />\n";
        echo "I am not a constructor in A.<br />\n";
    }
}

class B extends A
{
}

// Esto invocará a B() como un constructor
$b = new B;
?>
]]>
    </programlisting>
   </informalexample>
   
   <para>
    La función B() en la clase A repentinamente se volverá un
    constructor en la clase B, aunque nunca fue la intención que lo fuera.
    A PHP 4 no le importa si la función ha sido definida
    en la clase B, o si ha sido heredada.
   </para>
   
   <caution>
    <simpara>
     PHP no llama automáticamente a los constructores de la clase base
     desde un constructor de una clase derivada. Es su responsabilidad
     propagar la llamada a los constructores en la jerarquía superior 
     cuando sea apropiado.
    </simpara>
   </caution>
   
   <para>
    Los destructores son funciones que son invocadas automáticamente
    cuando un objeto es destruido, ya sea con <function>unset</function>
    o simplemente al salir del alcance. No existen destructores
    en PHP. En cambio, se puede utilizar <function>register_shutdown_function</function>
    para simular la mayoría de los efectos de los destructores.
   </para>
  </sect1>

 <sect1 xml:id="keyword.paamayim-nekudotayim"><!-- :-) -->
   <title>Operador de Resolución de Alcance (<literal>::</literal>)</title>

   <caution>
    <simpara>
     Lo siguiente es válido para PHP 4 y posteriores únicamente.
    </simpara>
   </caution>

   <para>
    Algunas veces es útil hacer referencia a funciones y variables
    en las clases base o hacer referencia a funciones que se encuentran en clases que 
    aún no tienen ninguna instancia. El operador <literal>::</literal>
    es utilizado para realizar esto.
   </para>
   
   <informalexample>
    <programlisting role="php">
<![CDATA[
<?php
class A {
    function example() {
        echo "I am the original function A::example().<br />\n";
    }
}

class B extends A {
    function example() {
        echo "I am the redefined function B::example().<br />\n";
        A::example();
    }
}

// no hay objetos de la clase A.
// esto imprimirá
//   I am the original function A::example().<br />
A::example();

// crear un objeto de clase B.
$b = new B;

// esto imprimirá
//   I am the redefined function B::example().<br />
//   I am the original function A::example().<br />
$b->example();
?>
]]>
    </programlisting>
   </informalexample>

   <para>
    El ejemplo de arriba invoca a la función <literal>example()</literal> en
    la clase A, pero no hay un objeto de la clase A, así que 
    no es posible escribir <literal>$a->example()</literal> o algo semejante. En vez de ello
    se invoca <literal>example()</literal> como una 'función de clase', es decir, como una
    función de la clase misma, no de un objeto de esa
    clase.
   </para>
   
   <para>
    Existen funciones de clase, pero no existen variables de clase.
    De hecho, no existe objeto alguno en el momento de la invocación.
    Siendo así, una función de clase no puede utilizar ninguna variable de objeto (pero
    puede utilizar variables locales y globales), y no puede utilizar
    <varname>$this</varname> para nada.
   </para>

   <para>
    En el ejemplo anterior, la clase B vuelve a definir la función
    <literal>example()</literal>. La definición original en la clase A queda desplazada
    y ya no se encuentra disponible, a menos que se haga referencia específicamente
    a la implementación de <literal>example()</literal> en la clase A empleando el
    operador ::. Se escribe <literal>A::example()</literal> para realizar esto (de hecho, se
    debe escribir <literal>parent::example()</literal>, tal como se muestra en la siguiente
    sección).
   </para>
   
   <para>
    En este contexto, existe un objeto actual y puede tener variables de
    objeto. Así, cuando se usen desde el INTERIOR de una función de objeto, se puede utilizar
    <varname>$this</varname> y las variables de objeto.
   </para>

 </sect1>

 <sect1 xml:id="keyword.parent">
   <title><literal>parent</literal></title>

  <para>
   Se puede encontrar que se escribe código que hace referencia a
   variables y funciones en las clases base. Esto es particularmente
   cierto si la clase derivada es un refinamiento
   o especialización de código en la clase base.
  </para>
  
  <para>
   En vez de utilizar el nombre de la clase base en el
   código, debe utilizarse el nombre especial
   <literal>parent</literal>, que hace referencia al nombre de la
   clase base tal como se especifica en la declaración <literal>extends</literal>
   de la clase. Al hacer esto, se evita utilizar el
   nombre de la clase base en más de una ubicación. Si el
   árbol de herencia llegase a cambiar durante la implementación, el
   cambio puede llevarse a cabo con facilidad simplemente cambiando la
   declaración <literal>extends</literal> de la clase.
  </para>

  <informalexample>
   <programlisting role="php">
<![CDATA[
<?php
class A {
    function example() {
        echo "I am A::example() and provide basic functionality.<br />\n";
    }
}

class B extends A {
    function example() {
        echo "I am B::example() and provide additional functionality.<br />\n";
        parent::example();
    }
}

$b = new B;

// Este ejemplo invocará a B::example(), que a su vez invocará a A::example().
$b->example();
?>
]]>
   </programlisting>
  </informalexample>
 </sect1>

 <sect1 xml:id="oop4.serialization">
  <title>Serialización de objetos - objetos en las sesiones</title>

  <para>
   <function>serialize</function> devuelve un string conteniendo una
   representación de flujo de bytes de cualquier valor que pueda ser almacenado en
   PHP. <function>unserialize</function> puede utilizar este string para
   recrear los valores originales de la variable. Al utilizar serialize para
   guardar un objeto, se guardarán todas las variables en el objeto.  Las
   las funciones en un objeto no serán guardadas, solamente el nombre de
   la clase.
  </para>
  
  <para>
   Para poder utilizar <function>unserialize</function> en un objeto, la
   clase de ese objeto necesita estar definida. Es decir, si se tiene un objeto
   <varname>$a</varname> de la clase A en <filename>page1.php</filename> y se serializa éste, se
   obtiene un string que hace referencia a la clase A y que contiene todos los valores de las variables
   contenidas en <varname>$a</varname>. Si se desea ser capáz de revertir la serialización
   de esto en <filename>page2.php</filename>, recreando <varname>$a</varname> de la clase A, la
   definición de la clase A debe estar presente en <filename>page2.php</filename>.
   Esto puede hacerse por ejemplo al colocar la definición de clase de la clase A
   en un fichero de include e incluyendo este fichero en ambas páginas
   <filename>page1.php</filename> y en <filename>page2.php</filename>.
  </para>
  
  <informalexample>
   <programlisting role="php">
<![CDATA[
<?php
// classa.inc:
  
  class A {
      var $one = 1;
    
      function show_one() {
          echo $this->one;
      }
  }
  
// page1.php:

  include("classa.inc");
  
  $a = new A;
  $s = serialize($a);
  // almacenar $s en algún lado donde page2.php pueda encontrarle.
  $fp = fopen("store", "w");
  fwrite($fp, $s);
  fclose($fp);

// page2.php:
  
  // esto es necesario para que unserialize funcione apropiadamente.
  include("classa.inc");

  $s = implode("", @file("store"));
  $a = unserialize($s);

  // ahora utilizar la función show_one() del objeto $a.  
  $a->show_one();
?>
]]>
   </programlisting>
  </informalexample>
  
  <para>
   Si se están utilizando sesiones y se emplea <function>session_register</function>
   para registrar objetos, estos objetos son serializados automáticamente
   al final de cada página de PHP, y la serialización les es revertida automáticamente en
   en cada una de las páginas siguientes. Esto significa básicamente que estos objetos
   pueden aparecer en cualquiera de las páginas una vez que se vuelven parte de la
   sesión.
  </para>
  
  <para>
   Es recomendado enfáticamente que se incluyan las definiciones
   de clase de semejantes objetos en todas las
   páginas, aun si no se usan estas clases en todas las
   páginas. Si no se hace y a un objeto se le revierte la
   serialización sin que su definición de clase esté presente,
   perderá su asociacón de clase y se volverá un objeto de la clase
   <classname>__PHP_Incomplete_Class_Name</classname> sin ninguna función disponible
   por completo, es decir, se volverá bastante inútil.
  </para>
  
  <para>
   Así que si en el ejemplo anterior <varname>$a</varname> se volviese parte de una sesión
   al ejecutar <literal>session_register("a")</literal>, se debería incluir el
   fichero <literal>classa.inc</literal> en todas las páginas, no sólo en <filename>page1.php</filename>
   y en <filename>page2.php</filename>.
  </para>
 </sect1>

 <sect1 xml:id="oop4.magic-functions">
  <title>Las funciones mágicas <literal>__sleep</literal> y <literal>__wakeup</literal></title>

  <para>
   <function>serialize</function> revisa si la clase tiene una función con
   el nombre mágico <literal>__sleep</literal>. Si es así, esa función es
   ejecutada antes de cualquier serialización. Puede limpiar el objeto
   y se supone que devuelva una matriz con los nombres de todas las variables
   de ese objeto que deberán ser serializadas.
   Si el método no devuelve nada, entonces &null; es serializado y
   E_NOTICE es emitida.
  </para>
  
  <para>
   La intención de utilizar <literal>__sleep</literal> es asentar datos
   pendientes o realizar tareas similares de limpieza. También la función es
   útil si se tienen objetos muy grandes que no necesitan ser
   guardados completamente.
  </para>
  
  <para>
   De manera correspondiente, <function>unserialize</function> revisa la
   presencia de una función con el nombre mágico de
   <literal>__wakeup</literal>. Si está presente, esta función puede
   reconstruir cualesquiera recursos que el objeto pueda tener.
  </para>
  
  <para>
    El propósito de utilizar <literal>__wakeup</literal> es
    reestablecer cualquier conexión a bases de datos que se pudiese haber perdido
    durante la serialización y realizar otras tareas de
    reinicialización.
  </para>
 </sect1>
  
 <sect1 xml:id="oop4.newref">
   <title>Referencias dentro del constructor</title>
   <para>
    Crear referencias dentro del cosntructor puede llevar a resultados
    confusos. Esta sección a manera de guía ayuda a evitar problemas.
 
    <informalexample>
     <programlisting role="php">
<![CDATA[
<?php
class Foo {
    function Foo($name) {
        // crear una referencia dentro de la matriz global $globalref
        global $globalref;
        $globalref[] = &$this;
        // hacer que el nombre sea el valor que ha sido pasado
        $this->setName($name);
        // y mostrarlo
        $this->echoName();
    }

    function echoName() {
        echo "<br />", $this->name;
    }
 
    function setName($name) {
        $this->name = $name;
    }
}
?>
]]>
    </programlisting>
   </informalexample>
  </para>
    
   <para>
    Revisar si hay alguna diferencia entre
    <varname>$bar1</varname> que ha sido creada usando el
    operador de copiado <literal>=</literal> y
    <varname>$bar2</varname> que ha sido creada utilzando el
    operador de referencia <literal>=&amp;</literal>...

    <informalexample>
     <programlisting role="php">
<![CDATA[
<?php
$bar1 = new Foo('set in constructor');
$bar1->echoName();
$globalref[0]->echoName();

/* salida:
set in constructor
set in constructor
set in constructor */

$bar2 =& new Foo('set in constructor');
$bar2->echoName();
$globalref[1]->echoName();

/* salida:
set in constructor
set in constructor
set in constructor */
?>
]]>
     </programlisting>
    </informalexample>
   </para>
   <para>
    Aparentemente no hay diferencia, pero de hecho existe una
    muy significativa: <varname>$bar1</varname> y
    <varname>$globalref[0]</varname> _NO_ están referenciadas, NO
    son la misma variable. Esto es porque "<literal>new</literal>" no
    devuelve una referencia por omisión, en vez de ello devuelve una copia.
    <note>
     <simpara>
      No hay pérdida de desempeño (ya que PHP 4 y superiores utilizan conteo
      de referencias) al devolver copias en vez de referencias. Al contrario
      la mayor parte del tiempo es mejor simplemente trabajar con copias
      en vez de referencias, porque crear referencias toma algo de
      tiempo mientras que crear copias virtualmente no toma tiempo (a menos que una
      de ellas sea un objeto o matriz grande y una de ellas es cambiada
      y la(las) otra(s) subsecuentemente también, entonces sería sabio
      usar referencias para cambiarlas a todas concurrentemente).
     </simpara>
    </note>
    Para probar lo que esta escrito aquí arriba observar el código siguiente.

    <informalexample>
     <programlisting role="php">
<![CDATA[
<?php
// ahora se cambiará el nombre. ¿Qué esperabas?
// se podría esperar que $bar1 y $globalref[0] ambas cambien sus nombres...
$bar1->setName('set from outside');

// como se mencionó antes este no es el caso.
$bar1->echoName();
$globalref[0]->echoName();

/* salida:
set from outside
set in constructor */

// veamos que es diferente con $bar2 y $globalref[1]
$bar2->setName('set from outside');

// afortunadamente no sólo son iguales, son la misma variable
// así $bar2->name y $globalref[1]->name son las mismas también
$bar2->echoName();
$globalref[1]->echoName();

/* salida:
set from outside
set from outside */
?>
]]>
     </programlisting>
    </informalexample>   
   </para>   
   <para>
   Otro ejemplo final, intente comprenderlo.
   
    <informalexample>
     <programlisting role="php">
<![CDATA[
<?php
class A {
    function A($i) {
        $this->value = $i;
        // intente entender por qué no es necesaria una referencia aquí
        $this->b = new B($this);
    }

    function createRef() {
        $this->c = new B($this);
    }

    function echoValue() {
        echo "<br />","class ",get_class($this),': ',$this->value;
    }
}


class B {
    function B(&$a) {
        $this->a = &$a;
    }

    function echoValue() {
        echo "<br />","class ",get_class($this),': ',$this->a->value;
    }
}

// intente entender por qué usar una copia simple aquí terminaría
// en un resultado no deseado en la línea marcada con *
$a =& new A(10);
$a->createRef();

$a->echoValue();
$a->b->echoValue();
$a->c->echoValue();

$a->value = 11;

$a->echoValue();
$a->b->echoValue(); // *
$a->c->echoValue();

?>
]]>
     </programlisting>
     &example.outputs;
     <screen>
<![CDATA[
class A: 10
class B: 10
class B: 10
class A: 11
class B: 11
class B: 11
]]>
     </screen>
    </informalexample>
   </para>
  </sect1>

  <sect1 xml:id="oop4.object-comparison">
   <title>Comparando objects</title>
  <para>
   En PHP 4, los objetos se comparan de una manera muy sencilla, entiéndase: Dos instancias
   de objeto son iguales si tienen los mismos atributos y valores, y son
   instancias de la misma clase. Reglas semejantes se aplican cuando se comparan dos
   objetos utilizando el operador de identidad (<literal>===</literal>).
  </para>
  <para>
   Si se fuese a ejecutar el código en el ejemplo siguiente:
   <example>
    <title>Ejemplo de comparación de objetos en PHP 4</title>
    <programlisting role='php'>
<![CDATA[
<?php
function bool2str($bool) {
    if ($bool === false) {
            return 'FALSE';
    } else {
            return 'TRUE';
    }
}

function compareObjects(&$o1, &$o2) {
    echo 'o1 == o2 : '.bool2str($o1 == $o2)."\n";
    echo 'o1 != o2 : '.bool2str($o1 != $o2)."\n";
    echo 'o1 === o2 : '.bool2str($o1 === $o2)."\n";
    echo 'o1 !== o2 : '.bool2str($o1 !== $o2)."\n";
}

class Flag {
    var $flag;

    function Flag($flag=true) {
            $this->flag = $flag;
    }
}

class SwitchableFlag extends Flag {

    function turnOn() {
        $this->flag = true;
    }

    function turnOff() {
        $this->flag = false;
    }
}

$o = new Flag();
$p = new Flag(false);
$q = new Flag();

$r = new SwitchableFlag();

echo "Compare instances created with the same parameters\n";
compareObjects($o, $q);

echo "\nCompare instances created with different parameters\n";
compareObjects($o, $p);

echo "\nCompare an instance of a parent class with one from a subclass\n";
compareObjects($o, $r);
?>
]]>
    </programlisting>
    &example.outputs;
    <screen>
<![CDATA[    
Compare instances created with the same parameters
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE

Compare instances created with different parameters
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE

Compare an instance of a parent class with one from a subclass
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
]]>
    </screen>
   </example>   
   El cual es el resultado que se esperaría obtener dadas las reglas de comparación
   anteriores. Unicamente instancias con los mismos valores para sus atributos
   y de la misma clase son consideradas como iguales e idénticas.
  </para>
  <para>
   Aun en casos en donde se tiene composición de objetos, se aplican las mismas reglas
   de comparación. En el ejemplo siguiente se crea una clase contenedora que almacena 
   una matriz asociativa de objetos <classname>Flag</classname>.
   <example>
    <title>Comparaciones de objetos compuestos en PHP 4</title>
    <programlisting role='php'>
<![CDATA[
<?php
class FlagSet {
    var $set;

    function FlagSet($flagArr = array()) {
        $this->set = $flagArr;
    }

    function addFlag($name, $flag) {
        $this->set[$name] = $flag;
    }

    function removeFlag($name) {
        if (array_key_exists($name, $this->set)) {
            unset($this->set[$name]);
        }
    }
}


$u = new FlagSet();
$u->addFlag('flag1', $o);
$u->addFlag('flag2', $p);
$v = new FlagSet(array('flag1'=>$q, 'flag2'=>$p));
$w = new FlagSet(array('flag1'=>$q));

echo "\nComposite objects u(o,p) and v(q,p)\n";
compareObjects($u, $v);

echo "\nu(o,p) and w(q)\n";
compareObjects($u, $w);
?>     
]]>
    </programlisting>
    &example.outputs;
    <screen>
<![CDATA[
Composite objects u(o,p) and v(q,p)
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE

u(o,p) and w(q)
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
]]>
    </screen>
   </example>
  </para>
 </sect1>
 </appendix>
 
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->
​

Reply via email to