Diferencia entre revisiones de «PHP Programación Orientada a obxectos»

De MediaWiki
Ir a la navegación Ir a la búsqueda
 
(No se muestran 58 ediciones intermedias de 2 usuarios)
Línea 64: Línea 64:
 
* As clases defínense empreñando a palabra clave class seguida do nome da clase e dun bloque de código entre chaves. A sintaxe é a seguinte:
 
* As clases defínense empreñando a palabra clave class seguida do nome da clase e dun bloque de código entre chaves. A sintaxe é a seguinte:
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="2,3,11" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="2,3,11" >
 
<?php
 
<?php
 
class SimpleClass
 
class SimpleClass
 
{
 
{
 
     // propiedade
 
     // propiedade
−
     public $var = 'valor por defecto';
+
     public string $var = 'valor por defecto';
  
 
     // métodos
 
     // métodos
Línea 89: Línea 89:
  
  
−
* Cada clase '''estará definida nun arquivo php que levará o seu nome'''.
+
* Cada clase, aínda que non é obrigatorio, '''a definiremos nun arquivo php separado que levará o seu nome'''.
−
: Así, por exemplo, a clase Alumno terá un arquivo de nome Alumno.class.php
+
: Así, por exemplo, a clase Alumno terá un arquivo de nome Alumno.php
−
: Como norma, '''a extensión dunha clase será .class.php'''.
+
: Como norma, a extensión dunha clase será:
 +
:* Se seguimos as recomendacións de [https://www.php-fig.org/psr/ PHP Standards Recommendations] soamente será necesario a extensión php. No exemplo anterior sería '''Alumno.php'''. <u>Esta opción es la empleada por los Framweworks de PHP para la carga automática de clases</u>.
 +
 
  
 
: Se dentro dunha páxina php necesito utilizar a clase Alumno terei que poñer:
 
: Se dentro dunha páxina php necesito utilizar a clase Alumno terei que poñer:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
<?php
 
<?php
−
   require_once('Alumno.class.php');
+
   require_once('Alumno.php');
 
?>
 
?>
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
 
:<u>Nota:</u> Lembrar as formas que [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Reutilizaci%C3%B3n_de_c%C3%B3digo:_Include_/_Require vimos para incluír arquivos externos].
 
:<u>Nota:</u> Lembrar as formas que [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Reutilizaci%C3%B3n_de_c%C3%B3digo:_Include_/_Require vimos para incluír arquivos externos].
−
: No exemplo estamos a supoñer que o arquivo 'Alumno.class.php' atópase no mesmo sitio que a clase php que está a facer uso del.
+
: No exemplo estamos a supoñer que o arquivo 'Alumno.php' atópase no mesmo sitio que a clase php que está a facer uso del.
  
  
 
* Vexamos un exemplo de clase:
 
* Vexamos un exemplo de clase:
−
: Arquivo: '''DiscosDuros.class.php'''
+
: Arquivo: '''DiscosDuros.php'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
<?php
 
<?php
  
 
class DiscosDuros {
 
class DiscosDuros {
−
     public $numSerie;
+
     public string  $numSerie;
−
     public $marca;
+
     public string $marca;
−
     public $capacidade=1;  // en TB
+
     public int $capacidade=1;  // en TB
 
      
 
      
 
     public function getCapacidadeKB(){
 
     public function getCapacidadeKB(){
Línea 120: Línea 122:
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
−
: Como vemos, temos definidos dous atributos, número de serie e capacidade. Por defecto, a capacidade de todos os obxectos que cremos desta clase será de 1TB.
+
: Como vemos, temos definidos tres atributos, número de serie,marca e capacidade. Por defecto, a capacidade de todos os obxectos que cremos desta clase será de 1TB.
 
: Tamén vemos a definición dun método (getCapacidadeKB) que devolve a capacidade do disco en KB. Dentro deste método sinalar o uso da variable '''$this'''.
 
: Tamén vemos a definición dun método (getCapacidadeKB) que devolve a capacidade do disco en KB. Dentro deste método sinalar o uso da variable '''$this'''.
  
Línea 141: Línea 143:
  
 
: Como vemos cada obxecto ten uns datos diferentes pero os dous chaman o mesmo método o cal está definido da mesma forma:
 
: Como vemos cada obxecto ten uns datos diferentes pero os dous chaman o mesmo método o cal está definido da mesma forma:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="6" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="6" >
 
<?php
 
<?php
 
class ContaBancaria {
 
class ContaBancaria {
−
     public $saldo;
+
     public float $saldo;
  
 
     public function devolverSaldo(){
 
     public function devolverSaldo(){
Línea 159: Línea 161:
 
* Para non ter que repetir un include ao principio de cada páxinas por cada unha das clases que necesitemos, podemos facer uso da [http://php.net/manual/es/language.oop5.autoload.php autocarga de clases].
 
* Para non ter que repetir un include ao principio de cada páxinas por cada unha das clases que necesitemos, podemos facer uso da [http://php.net/manual/es/language.oop5.autoload.php autocarga de clases].
 
: Do que se trata é de que cando fagamos uso dunha clase, a páxina PHP a inclúa automaticamente sen ter que facelo nos manualmente. Para iso podemos facer uso da...
 
: Do que se trata é de que cando fagamos uso dunha clase, a páxina PHP a inclúa automaticamente sen ter que facelo nos manualmente. Para iso podemos facer uso da...
 +
* Antigamente se recomendaba que estas clases tivera no nome un sufixo '''.class''' da forma NomeClases.class.php.
 +
: Na actualidade, se seguimos o [stándard indicado por PSR (PHP Standard Recommendations) https://www.php-fig.org/psr/] xa non é necesario.
 +
: Se seguimos o estándard de nomenclatura (PSR-4), as clases levan extensión .php sen empregar .class, da forma: '''NomeClase.php'''.
  
 
* [http://php.net/manual/es/function.spl-autoload-register.php Función  sql-autoload-register].
 
* [http://php.net/manual/es/function.spl-autoload-register.php Función  sql-autoload-register].
 
: Exemplo:
 
: Exemplo:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="6,2-4" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="6,2-4" >
 
<?php
 
<?php
 
     function cargadorClases($class) {
 
     function cargadorClases($class) {
−
         require $class . '.class.php';
+
         require $class . '.php';
 
     }
 
     }
  
Línea 179: Línea 184:
 
* Podemos ter o código anterior dentro dun arquivo de include e incluílo por cada páxina que faga uso de clases.
 
* Podemos ter o código anterior dentro dun arquivo de include e incluílo por cada páxina que faga uso de clases.
 
: Así:
 
: Así:
−
'''Arquivo: '''IncluirClases.inc.php''':
+
'''Arquivo: incluir-clases.php''':
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
<?php
 
<?php
 
     function cargadorClases($class) {
 
     function cargadorClases($class) {
−
         require $class . '.class.php';
+
         require $class . '.php';
 
     }
 
     }
  
 
     spl_autoload_register('cargadorClases');
 
     spl_autoload_register('cargadorClases');
  
 +
</syntaxhighlight>
 +
 +
'''Arquivo: DiscoDuros.php'''
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
<?php
 +
 +
class DiscosDuros {
 +
 +
    public string $numSerie;
 +
    public string $marca;
 +
    public string $capacidade=1;  // en TB
 +
 +
    public function getCapacidadeKB(): int {
 +
        return $this->capacidade*1024*1024;
 +
    }
 +
 +
}
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
  
−
: Páxina '''Exemplo.php'''.
+
: Páxina '''exemplo.php'''.
 
: Vai facer uso da clase DiscosDuros.
 
: Vai facer uso da clase DiscosDuros.
−
::<syntaxhighlight lang="java" line enclose="div" highlight="2" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="2" >
 
<?php
 
<?php
−
     include 'IncluirClases.inc.php';
+
     include 'incluir-clases.php';
 
?>
 
?>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
Línea 221: Línea 243:
  
 
* Para crear un obxecto dunha clase usaremos a palabra '''new''' seguido do nome da clase. Isto devolverá un obxecto (instancia) da clase:
 
* Para crear un obxecto dunha clase usaremos a palabra '''new''' seguido do nome da clase. Isto devolverá un obxecto (instancia) da clase:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="2,3" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="2,3" >
 
<?php
 
<?php
 
   $obxecto1 = new Clase();
 
   $obxecto1 = new Clase();
Línea 233: Línea 255:
 
* Vexamos un exemplo:
 
* Vexamos un exemplo:
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="19,20" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="19,20" >
 
<?php
 
<?php
 
     function cargadorClases($class) {
 
     function cargadorClases($class) {
−
         require $class . '.class.php';
+
         require $class . '.php';
 
     }
 
     }
  
Línea 266: Línea 288:
 
* Unha vez que temos un obxecto dunha clase xa podemos acceder as súas propiedades e métodos.
 
* Unha vez que temos un obxecto dunha clase xa podemos acceder as súas propiedades e métodos.
 
: Para iso temos que utilizar o operador '''->''' desta forma:
 
: Para iso temos que utilizar o operador '''->''' desta forma:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
  obxecto1->propiedade;
 
  obxecto1->propiedade;
 
  obxecto1->nomeMétodo();
 
  obxecto1->nomeMétodo();
Línea 272: Línea 294:
  
 
* Vexamos un exemplo:
 
* Vexamos un exemplo:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="3,4,6,8,10,13,14,16,18,20" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="3,4,6,8,10,13,14,16,18,20" >
 
         <?php
 
         <?php
 
             $disco1 = new DiscosDuros();
 
             $disco1 = new DiscosDuros();
Línea 300: Línea 322:
 
* Esta forma de acceder tamén pode empregarse dentro da clase para acceder aos seus propio métodos e atributos, pero utilizando a palabra reservada '$this'.
 
* Esta forma de acceder tamén pode empregarse dentro da clase para acceder aos seus propio métodos e atributos, pero utilizando a palabra reservada '$this'.
 
* Vexamos un exemplo:
 
* Vexamos un exemplo:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="9,12,16" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="9,12,16" >
 
<?php
 
<?php
  
 
class DiscosDuros {
 
class DiscosDuros {
−
     public $numSerie;
+
     public string $numSerie;
−
     public $marca;
+
     public string $marca;
−
     public $capacidade=1;  // en TB
+
     public int $capacidade=1;  // en TB
 
      
 
      
−
     public function getCapacidadeKB(){
+
     public function getCapacidadeKB(): int {
 
         return $this->capacidade*1024*1024;
 
         return $this->capacidade*1024*1024;
 
     }
 
     }
−
     public function getCapacidadeBytes(){
+
     public function getCapacidadeBytes(): int {
 
         return $this->getCapacidadeKB()*1024;
 
         return $this->getCapacidadeKB()*1024;
 
     }
 
     }
 
      
 
      
−
     public function getMarca(){
+
     public function getMarca(): string {
 
         return $this->marca;
 
         return $this->marca;
 
     }
 
     }
Línea 323: Línea 345:
  
  
−
'''Fai os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Definici.C3.B3n_de_clases._Creaci.C3.B3n_de_obxectos_e_acceso_a_variables_e_m.C3.A9todos neste punto]'''.
+
* A este tipo de propiedades/métodos soen denominarse 'de instancia'.
 +
: Cada obxecto ten un valor gardado diferente ao dos demais.
 +
 
 +
 
  
−
== Herdanza ==
 
  
−
* Na POO existen tres propiedades fundamentais: Herdanda, Polimorfismo e Encapsulación.
+
'''Fai os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Definici.C3.B3n_de_clases._Creaci.C3.B3n_de_obxectos_e_acceso_a_variables_e_m.C3.A9todos neste punto]'''. Solamente os da sección 'Definición de clases. Creación de obxectos e acceso a variables e métodos'.
  
−
* O concepto de herdanza é moi parecido ao que temos nos. Cando creamos unha clase que herda doutra, dita clase poderá acceder ás propiedades e métodos da clase pai.
+
== Mantemento do estado ==
  
−
: A clase pai denomínase superclase e a clase filla subclase.
+
* Para poder gardar un obxecto de forma persistente (que non se perda a información que ten e poidamos recuperala) é necesario 'transformalo' a unha cadea de texto que contén un fluxo de bytes, nun proceso que se chama serialización.
 +
: Isto é necesario xa que cando gardamos algo (nunha base de datos, ou nunha variable de sesión) é necesario que dita información pertenza a un tipo de datos, pero un obxecto está formado por propiedades con diferentes tipos de datos.
  
−
* A sintaxe é a seguinte:
+
* O procedemento é moi sinxelo:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="9" >
+
:* Para convertilo empregamos a [https://www.php.net/manual/es/function.serialize.php función serialice()] da forma: $s = serialice($a);  sendo $a un obxecto dunha clase.
−
  class Pai {
+
:: Agora podemos gardar $s nunha base de datos por exemplo.
−
   public $var1;
+
:* Para volvelo a convertir a un obxecto dunha clase, empregamos a [https://www.php.net/manual/es/function.unserialize.php función unserialice()] da forma: $a = unserialice($s); sendo $s o obxecto previamente serializado.
−
   public $var2;
+
 
 +
 
 +
 
 +
* No caso das variables de sesión, PHP xa serializa/deserializa un obxecto e non necesitamos empregar as funcións anteriores.
 +
: Por exemplo:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
 
 +
session_start();
 +
$_SESSION['producto'] = $p;
 +
 
 +
 
 +
......
 +
 
 +
 
 +
 
 +
$p = $_SESSION['producto'];
 +
 
 +
</syntaxhighlight>
 +
 
 +
 
 +
<br />
 +
 
 +
== Herdanza ==
 +
 
 +
* Na POO existen tres propiedades fundamentais: Herdanda, Polimorfismo e Encapsulación.
 +
 
 +
* O concepto de herdanza é moi parecido ao que temos nos. Cando creamos unha clase que herda doutra, dita clase poderá acceder ás propiedades e métodos da clase pai.
 +
 
 +
: A clase pai denomínase superclase e a clase filla subclase.
 +
 
 +
* A sintaxe é a seguinte:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="9" >
 +
  class Pai {
 +
   public string $var1;
 +
   public string $var2;
 
    
 
    
−
   public function imprimirVar1(){
+
   public function imprimirVar1(): void {
−
     echo $var1;
+
     echo string $var1;
 
   }
 
   }
 
  }
 
  }
 
  class Filla extends Pai {
 
  class Filla extends Pai {
−
   public $var3;
+
   public string $var3;
−
   public function imprimirVar3(){
+
   public function imprimirVar3(): void {
 
     echo $var3;
 
     echo $var3;
 
   }
 
   }
Línea 355: Línea 414:
 
* Se agora creamos un obxecto da clase Filla, poderemos acceder aos atributos e métodos da clase pai. Así:
 
* Se agora creamos un obxecto da clase Filla, poderemos acceder aos atributos e métodos da clase pai. Así:
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
   $filla1 = new Filla();
 
   $filla1 = new Filla();
  
Línea 377: Línea 436:
 
* Exemplo de herdanza:
 
* Exemplo de herdanza:
  
−
'''Arquivo:''' Componentes.class.php
+
'''Arquivo:''' Componentes.php
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
<?php
 
<?php
  
 
class Componentes {
 
class Componentes {
−
     public $numSerie;
+
     public string $numSerie;
−
     public $nome;
+
     public string $nome;
−
     public $prezo;
+
     public float $prezo;
−
     public $marca;
+
     public string $marca;
  
  
−
     public function getNumSerie(){
+
     public function getNumSerie(): string {
 
         return $this->numSerie;
 
         return $this->numSerie;
 
     }
 
     }
−
     public function getNome(){
+
     public function getNome(): string {
 
         return $this->nome;
 
         return $this->nome;
 
     }
 
     }
−
     public function getPrezo(){
+
     public function getPrezo(): float {
 
         return $this->prezo;
 
         return $this->prezo;
 
     }
 
     }
−
     public function getMarca(){
+
     public function getMarca(): string {
 
         return $this->marca;
 
         return $this->marca;
 
     }
 
     }
Línea 405: Línea 464:
  
  
−
'''Arquivo:''' DiscosDuros.class.php
+
'''Arquivo:''' DiscosDuros.php
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
<?php
 
<?php
  
 
class DiscosDuros extends Componentes{
 
class DiscosDuros extends Componentes{
−
     public $capacidade=1;  // en TB
+
     public int $capacidade=1;  // en TB
  
−
     public function getCapacidadeKB(){
+
     public function getCapacidadeKB(): int {
 
         return $this->capacidade*1024*1024;
 
         return $this->capacidade*1024*1024;
 
     }
 
     }
−
     public function getCapacidadeBytes(){
+
     public function getCapacidadeBytes(): int {
 
         return $this->getCapacidadeKB()*1024;
 
         return $this->getCapacidadeKB()*1024;
 
     }
 
     }
Línea 422: Línea 481:
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
−
'''Arquivo:''' Principal.php
+
'''Arquivo:''' principal.php
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
<?php
 +
ini_set('display_errors', 1);
 +
ini_set('display_startup_errors', 1);  // Non debería ser necesario xa que amosa posibles erros de configuración no php.ini ou erros antes da execución do script, pero podemos poñelo por se acaso.
 +
error_reporting(E_ALL);
 +
 
 +
include 'incluir-clases.php';
 +
?>
 +
 
 +
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +
 
 +
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 
 +
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
 +
 
 +
    <head>
 +
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 +
        <title>Exemplos de uso de clases</title>
 +
    </head>
 
     <body>
 
     <body>
 
         <?php
 
         <?php
Línea 433: Línea 510:
 
             printf("NUM.SERIE %s",$disco1->numSerie);
 
             printf("NUM.SERIE %s",$disco1->numSerie);
 
             echo "<br />";
 
             echo "<br />";
−
             printf("MARCA %f",$disco1->marca);
+
             printf("MARCA %s",$disco1->marca);
 
             echo "<br />";
 
             echo "<br />";
 
             printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());
 
             printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());
Línea 454: Línea 531:
 
         ?>
 
         ?>
 
     </body>
 
     </body>
 +
</html>
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
Línea 471: Línea 549:
  
  
−
'''Facede os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Herdanza neste punto]'''.
+
'''<u>Nota:</u>''' Se queres imprimir todos os datos dun obxecto podedes empregar a [https://www.php.net/manual/es/function.var-dump.php función var_dump(obxecto)].
  
 +
 +
'''Facede os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Herdanza neste punto]'''. Soamente os da sección 'Herdanza'.
  
 
== Construtores ==
 
== Construtores ==
Línea 482: Línea 562:
 
* A forma de definir un construtor é:
 
* A forma de definir un construtor é:
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
void __construct ([ mixed $args = "" [, $... ]] )
 
void __construct ([ mixed $args = "" [, $... ]] )
 
</syntaxhighlight>  
 
</syntaxhighlight>  
Línea 491: Línea 571:
 
* Aplicamos este concepto ao exercicio anterior:
 
* Aplicamos este concepto ao exercicio anterior:
  
−
'''Arquivo: Componentes.class.php'''
+
'''Arquivo: Componentes.php'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="10,15" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="10,15" >
 
     <?php
 
     <?php
  
 
     class Componentes {
 
     class Componentes {
−
         public $numSerie;
+
         public string $numSerie;
−
         public $nome;
+
         public string $nome;
−
         public $prezo;
+
         public float $prezo;
−
         public $marca;
+
         public string $marca;
  
  
−
         function __construct($numSerie,$nome,$prezo,$marca) {
+
         function __construct(string $numSerie, string $nome, float $prezo, string $marca) {
 
             $this->numSerie=$numSerie;
 
             $this->numSerie=$numSerie;
 
             $this->nome=$nome;
 
             $this->nome=$nome;
Línea 513: Línea 593:
 
   
 
   
 
'''Arquivo: Principal.php'''
 
'''Arquivo: Principal.php'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="2,15" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="2,15" >
 
         <?php
 
         <?php
 
             $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete"); // Tamén ten o da clase Compoñente
 
             $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete"); // Tamén ten o da clase Compoñente
Línea 551: Línea 631:
  
 
: Apliquemos isto ao exemplo anterior:
 
: Apliquemos isto ao exemplo anterior:
−
'''Arquivo: DiscoDuros.class.php'''
+
'''Arquivo: DiscoDuros.php'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="5,6,7" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="5,6,7" >
 
<?php
 
<?php
 
class DiscosDuros extends Componentes{
 
class DiscosDuros extends Componentes{
−
     public $capacidade=1;  // en TB
+
     public int $capacidade=1;  // en TB
 
   
 
   
−
     function __construct($numSerie, $nome, $prezo, $marca,$capacidade) {
+
     function __construct(string $numSerie, string $nome, float $prezo, string $marca, int $capacidade) {
 
         parent::__construct($numSerie, $nome, $prezo, $marca);
 
         parent::__construct($numSerie, $nome, $prezo, $marca);
 
         $this->capacidade=$capacidade;
 
         $this->capacidade=$capacidade;
 
     }
 
     }
−
     public function getCapacidadeKB(){
+
     public function getCapacidadeKB(): int {
 
         return $this->capacidade*1024*1024;
 
         return $this->capacidade*1024*1024;
 
     }
 
     }
−
     public function getCapacidadeBytes(){
+
     public function getCapacidadeBytes(): int {
 
         return $this->getCapacidadeKB()*1024;
 
         return $this->getCapacidadeKB()*1024;
 
     }
 
     }
Línea 576: Línea 656:
  
 
'''Arquivo: Principal.php'''
 
'''Arquivo: Principal.php'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="2,14" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="2,14" >
 
         <?php
 
         <?php
 
             $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete",1); // Tamén ten o da clase Compoñente
 
             $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete",1); // Tamén ten o da clase Compoñente
Línea 613: Línea 693:
 
: Isto en PHP non o podemos facer.
 
: Isto en PHP non o podemos facer.
  
−
: Para solucionalo (código obtido [http://php.net/manual/es/language.oop5.decon.php deste enlace]) podemos implementar o seguinte código:
+
: Para solucionalo, temos que empregar un único constructor no que imos obter o número de parámetros que enviamos e en función diso, inicializaremos as propiedades correspondentes.
 +
: As funcións que temos que empregar dentro de __construct son:
 +
:* [https://www.php.net/manual/es/function.func-get-args.php Función func_get_args()] que nos devolve nun array os parámetros enviados ao constructor.
 +
:* [https://www.php.net/manual/es/function.func-num-args.php Función func_num_args()] que nos devolve o número de parámetros do constructor.
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
 
−
     function __construct()
+
* Unha forma sinxela de facelo sería o seguinte:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
class Proba
 +
{
 +
$atrib1;
 +
$atrib2;
 +
 
 +
function __construct() {
 +
      $args = func_get_args();
 +
      $num = func_num_args();
 +
      switch ($num) {
 +
            case 0: // Chamamos ao constructor sen parámetros
 +
                $this->$atrib1 = 10;
 +
                $this->$atrib2 = 10;
 +
                break;
 +
            case 1:  // Chamamos ao constructor con 1 parámetro
 +
                $this->atrib1= func_get_arg(0); // Os argumentos empezan en 0
 +
                $this->atrib2 = 10;  // Valor por defecto
 +
                break;
 +
            case 2: // Chamamos ao constructor con 2 parámetros
 +
                $this->atrib1= func_get_arg(0);
 +
                $this->atrib2= func_get_arg(1);
 +
        }
 +
 
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 
 +
 
 +
 
 +
 
 +
 
 +
<br />
 +
Outra forma máis complexa (código obtido [http://php.net/manual/es/language.oop5.decon.php deste enlace]) a podemos implementar có seguinte código:
 +
 
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
     function __construct()
 
       {
 
       {
 
           $a = func_get_args();
 
           $a = func_get_args();
Línea 629: Línea 748:
 
: Así se eu crea un obxecto dunha clase no que quero enviar dous argumentos poñería:
 
: Así se eu crea un obxecto dunha clase no que quero enviar dous argumentos poñería:
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
  $obx1 = new Clase($val1,$val2);
 
  $obx1 = new Clase($val1,$val2);
 
</syntaxhighlight>  
 
</syntaxhighlight>  
Línea 635: Línea 754:
 
: Isto chamará a o construtor por defecto o cal chamará a outro método:
 
: Isto chamará a o construtor por defecto o cal chamará a outro método:
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
  function __construct2($par1,$par2){
 
  function __construct2($par1,$par2){
 
  }
 
  }
Línea 646: Línea 765:
  
  
−
'''Arquivo: DiscoDuros.class.php'''
+
'''Arquivo: DiscoDuros.php'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
<?php
 
<?php
  
 
class DiscosDuros extends Componentes{
 
class DiscosDuros extends Componentes{
−
     public $capacidade=1;  // en TB
+
     public int $capacidade=1;  // en TB
  
−
     function __construct()
+
   
−
      {
+
     function __construct() {
−
          $a = func_get_args();
+
      $args = func_get_args();
−
          $i = func_num_args();
+
      $num = func_num_args();
−
          if (method_exists($this,$f='__construct'.$i)) {
+
      switch ($num) {  //ORDEN CONSTRUCTOR SUPERIOR => $numSerie,$nome,$prezo,$marca
−
              call_user_func_array(array($this,$f),$a);
+
            case 3: // Enviamos 3 datos: num_serie (arg(0)), nome (arg(1)) e marca (arg(2))
−
          }
+
                parent::__construct(func_get_arg(0), func_get_arg(1), 500, func_get_arg(2)); // Enviamos un prezo por defecto en caso de non enviar o dato
−
      }
+
                $this->capacidade = 100;    // Podemos dar un valor por defecto ao dato non enviado
−
   
+
                break;
−
    function __construct4($numSerie, $nome, $marca,$capacidade) {
+
            case 4:  // Enviamos 4 datos: num_serie (arg(0)), nome (arg(1)), marca (arg(2)) e capacidade (arg(3))
−
        parent::__construct($numSerie, $nome, 0, $marca);
+
                parent::__construct(func_get_arg(0), func_get_arg(1), 0, func_get_arg(2));  // Neste caso enviamos 0 como prezo por defecto
−
        $this->capacidade=$capacidade;
+
                $this->capacidade = func_get_arg(3);
−
         $this->prezo=100;
+
                break;
 +
            case 5:  // Chamamos ao constructor con 5 parámetros: num_serie (arg(0)), nome (arg(1)), prezo (arg(2)), marca (arg(3)) e capacidade (arg(4))
 +
                parent::__construct(func_get_arg(0), func_get_arg(1), func_get_arg(2),func_get_arg(3));
 +
                $this->capacidade = func_get_arg(4);
 +
                break;
 +
         }
 +
    }
 +
 
 +
    public function getCapacidadeKB(): int{
 +
        return $this->capacidade*1024*1024;
 
     }
 
     }
−
 
+
     public function getCapacidadeBytes(): int{
−
     function __construct5($numSerie, $nome, $prezo, $marca,$capacidade) {
+
         return $this->getCapacidadeKB()*1024;
−
         parent::__construct($numSerie, $nome, $prezo, $marca);
 
−
        $this->capacidade=$capacidade;
 
 
     }
 
     }
  
 +
}
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
  
 
* Agora podemos chamar aos dos construtores:
 
* Agora podemos chamar aos dos construtores:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
   $disco1 = new DiscosDuros("1111A","Disco Duro","Seagete",2);  
 
   $disco1 = new DiscosDuros("1111A","Disco Duro","Seagete",2);  
 
   $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
 
   $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
=== Destructores ===
 
  
−
* Ao igual que os construtores tamén dispoñemos dun método 'especial' denominado '''destrutor''' o cal se chama cando se deixa de ter referencias a un obxecto.
 
−
: Cando remata o script todas as referencias pérdense e polo tanto se chamará ao método __destructor.
 
  
−
: Vexamos un exemplo:
+
=== Constructores en clases fillas ===
−
'''Arquivo: Componentes.class.php'''
+
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="31-33" >
+
* Cando temos unha xerarquía de clases en forma de herdanza, cando unha clase filla define un constructor '''ten que chamar explícitamente''' ao constructor da clase pai coa forma: '''parent::__construct(parámetros)'''.
−
    <?php
 
  
−
    class Componentes {
+
: Por exemplo:
−
        static $numComponentes = 0;
+
: '''Clase Pai:'''
−
       
+
::<syntaxhighlight lang="java" enclose="div" highlight="4-7" >
−
        public $numSerie;
+
class ArchivoBase {
−
        public $nome;
+
    protected $handle;
−
        public $prezo;
 
−
        public $marca;
 
  
 +
    public function __construct($ruta) {
 +
        echo "Abriendo archivo...\n";
 +
        $this->handle = fopen($ruta, 'w');
 +
    }
  
−
        function __construct($numSerie,$nome,$prezo,$marca) {
+
    public function escribir($texto) {
−
            $this->numSerie=$numSerie;
+
        fwrite($this->handle, $texto . "\n");
−
            $this->nome=$nome;
+
     }
−
            $this->prezo=$prezo;
+
 
−
            $this->marca=$marca;
+
}
−
        }
+
</syntaxhighlight>
−
      
+
 
−
        public function getNumSerie(){
+
 
−
            return $this->numSerie;
+
: '''Clase filla:'''
−
        }
+
::<syntaxhighlight lang="java" enclose="div" highlight="5" >
−
        public function getNome(){
+
class Logger extends ArchivoBase {
−
            return $this->nome;
 
−
        }
 
−
        public function getPrezo(){
 
−
            return $this->prezo;
 
−
        }
 
−
        public function getMarca(){
 
−
            return $this->marca;
 
−
        }
 
−
        function __destruct(){
 
−
            echo "<br />Acabouse";
 
−
        }
 
  
 +
    public function __construct($ruta) {
 +
        echo "Logger iniciado\n";
 +
        parent::__construct($ruta);
 
     }
 
     }
−
</syntaxhighlight>
 
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="13" >
+
    public function log($mensaje) {
−
        <?php
+
        $this->escribir($mensaje);
−
            $disco1 = new DiscosDuros("1111A","Disco Duro","Seagete",2); // Tamén ten o da clase Compoñente
+
    }
−
            echo "<br />";
+
−
            printf("NUM.SERIE %s",$disco1->numSerie);
+
}
−
            echo "<br />";
+
</syntaxhighlight>
−
            printf("MARCA %s",$disco1->marca);
+
 
−
            echo "<br />";
 
−
            printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());
 
−
            echo "<br />";
 
−
            printf("PREZO %s euros",number_format($disco1->getPrezo(),2));
 
  
−
            echo "<br />";
 
−
            $disco1=null;
 
−
            echo "<br />";
 
−
            echo "Segundo disco";
 
−
            echo "<br />";
 
−
            $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
 
−
            echo "<br />";
 
−
            printf("NUM.SERIE %s",$disco2->numSerie);
 
−
            echo "<br />";
 
−
            printf("MARCA %s",$disco2->marca);
 
−
            echo "<br />";
 
−
            printf("CAPACIDADE %s EN KB",$disco2->getCapacidadeKB());           
 
−
            echo "<br />";
 
−
            printf("PREZO %s euros", number_format($disco2->getPrezo(),2));
 
−
        ?>
 
  
−
</syntaxhighlight>
 
  
−
: Dará como resultado:
+
'''Facede os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Construtores neste punto]'''. Soamente os da sección 'Constructores'.
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="5,11" >
 
−
NUM.SERIE 1111A
 
−
MARCA Seagete
 
−
CAPACIDADE 2097152 EN KB
 
−
PREZO 100.00 euros
 
−
Acabouse
 
−
Segundo disco
 
  
−
NUM.SERIE 2222B
 
−
MARCA Hitachi
 
−
CAPACIDADE 6291456 EN KB
 
−
PREZO 150.73 euros Acabouse
 
−
</syntaxhighlight>
 
  
 +
<br />
 +
== Destructores ==
  
−
'''Facede os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Construtores neste punto]'''
+
* Ao igual que os construtores tamén dispoñemos dun método 'especial' denominado '''destrutor''' o cal se chama cando se deixa de ter referencias a un obxecto.
 +
: Cando remata o script todas as referencias pérdense e polo tanto se chamará ao método __destruct.
 +
: Non temos control sobre 'cando' se vai chamar a dito método.  
 +
: Normalmente o empregaremos nos exemplos para levar constancia de 'cantos' obxectos creamos dunha clase por darlle unha funcionalidade nos nosos exemplos, pero sen ten un control de cando se chama non o empregaremos nunha situación real.
 +
: Normalmente se emprega para liberar recursos ou facer algún tipo de log para cando se destrúa un obxecto.
  
−
== Polimorfismo e Sobrecarga ==
 
  
−
=== Polimorfismo ===
+
: Vexamos un exemplo:
−
* Outra das propiedades da POO é o '''Polimorfismo'''.
+
'''Arquivo: Componentes.php'''
−
: Normalmente o polimorfismo dáse en clases que manteñan unha relación de herdanza, aínda que tamén se pode dar en outro tipo de relacións (por exemplo utilizando [https://es.wikipedia.org/wiki/Interfaz_(Java) interfaces]).
+
::<syntaxhighlight lang="java" enclose="div" highlight="31-33" >
 +
    <?php
  
−
: Basicamente, é a capacidade que teñen as clase de definir métodos có mesmo nome e o mesmo número (e tipo en outras linguaxes) de argumentos.
+
    class Componentes {
−
: Cando un obxecto chame a dito método ou use unha propiedade, saberá que método/propiedade utilizar en base a súa pertenza a un tipo de clase determinado.
+
        static int $numComponentes = 0;
 +
       
 +
        public string $numSerie;
 +
        public string $nome;
 +
        public float $prezo;
 +
        public string $marca;
  
−
* Vexamos un exemplo aplicado ao caso dos DiscosDuros.
 
−
: Imaxinemos que creamos un método de nome 'comprobarDatos' que o que fai é que no caso dos DiscosDuros, mira que a capacidade teña un valor positivo e no caso dos Compoñenetes, o prezo teña un valor positivo. Devolverá 1 ou 0 dependendo do valor.
 
  
−
: Se eu creo un obxecto da clase DiscosDuros e chamo a dito método, chamará ao definido na clase DiscosDuros por pertencer a ela. Dende a clase DiscosDuros vou poder chamar ao método da clase superior utilizando a expresión '''parent::'''.
+
        function __construct(string $numSerie, string $nome, float $prezo, string $marca) {
 +
            $this->numSerie=$numSerie;
 +
            $this->nome=$nome;
 +
            $this->prezo=$prezo;
 +
            $this->marca=$marca;
 +
        }
 +
   
 +
        public function getNumSerie(): string{
 +
            return $this->numSerie;
 +
        }
 +
        public function getNome(): string{
 +
            return $this->nome;
 +
        }
 +
        public function getPrezo(): float{
 +
            return $this->prezo;
 +
        }
 +
        public function getMarca(): string{
 +
            return $this->marca;
 +
        }
 +
        function __destruct(){
 +
            echo "<br />Acabouse";
 +
        }
  
−
'''Arquivo: DiscosDuros.class.php'''
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
<?php
 
−
 
−
class DiscosDuros extends Componentes{
 
−
 
−
    .........
 
−
    public function comprobarDatos(){
 
−
        if (parent::comprobarDatos()==0) return 0;
 
−
        if ($this->capacidade < 0) {
 
−
            echo "<br />Capacidade negativa !!!<br />";
 
−
            return 0;
 
−
        } else {
 
−
            return 1;
 
−
        }
 
 
     }
 
     }
−
}
 
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
 +
::<syntaxhighlight lang="java" enclose="div" highlight="13" >
 +
        <?php
 +
            $disco1 = new DiscosDuros("1111A","Disco Duro","Seagete",2); // Tamén ten o da clase Compoñente
 +
            echo "<br />";
 +
            printf("NUM.SERIE %s",$disco1->numSerie);
 +
            echo "<br />";
 +
            printf("MARCA %s",$disco1->marca);
 +
            echo "<br />";
 +
            printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());
 +
            echo "<br />";
 +
            printf("PREZO %s euros",number_format($disco1->getPrezo(),2));
  
−
'''Arquivo: Componentes.class.php'''
+
            echo "<br />";
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
            $disco1=null;
−
<?php
+
            echo "<br />";
−
    class Componentes {
+
            echo "Segundo disco";
−
        ...................
+
            echo "<br />";
−
        public function comprobarDatos(){
+
            $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
−
             if ($this->prezo<0) {
+
            echo "<br />";
−
                echo "<br />Prezo negativo!!!<br />";
+
            printf("NUM.SERIE %s",$disco2->numSerie);
−
                return 0;
+
            echo "<br />";
−
            }
+
             printf("MARCA %s",$disco2->marca);
−
            else {
+
            echo "<br />";
−
                return 1;
+
            printf("CAPACIDADE %s EN KB",$disco2->getCapacidadeKB());           
−
            }
+
            echo "<br />";
−
        }
+
            printf("PREZO %s euros", number_format($disco2->getPrezo(),2));
 +
        ?>
 +
 
 +
</syntaxhighlight>
 +
 
 +
: Dará como resultado:
 +
 
 +
::<syntaxhighlight lang="java" enclose="div" highlight="5,11" >
 +
NUM.SERIE 1111A
 +
MARCA Seagete
 +
CAPACIDADE 2097152 EN KB
 +
PREZO 100.00 euros
 +
Acabouse
 +
Segundo disco
  
−
    }
+
NUM.SERIE 2222B
 +
MARCA Hitachi
 +
CAPACIDADE 6291456 EN KB
 +
PREZO 150.73 euros Acabouse
 
</syntaxhighlight>
 
</syntaxhighlight>
  
  
−
'''Arquivo: Principal.php'''
+
<br />
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
=== Destructores en clases fillas===
−
<?php
+
 
−
            $disco1 = new DiscosDuros();
+
* Ao igual que no caso dos constructores, se temos unha xerarquía de clases relacionadas pola herdanza, se sobreescribimos un __destruct dunha filla, esta debe chamar explicitamente ao __destruct da clase pai para que se execute.
−
            $disco1->prezo=-100;
+
 
−
            $disco1->capacidade=10;
 
−
            printf("O Prezo é negativo. Datos correctos?:%b",$disco1->comprobarDatos());
 
−
            $disco1->prezo=100;
 
−
            $disco1->capacidade=-10;
 
−
            printf("Capacidade negativa. Datos correctos?:%b",$disco1->comprobarDatos());
 
−
?>
 
−
</syntaxhighlight>
 
  
−
'''Saída:'''
+
: Por exemplo:
−
::<syntaxhighlight lang="java" enclose="div" highlight="" >
+
: '''Clase Pai:'''
−
Prezo negativo!!!
+
::<syntaxhighlight lang="java" enclose="div" highlight="4-7" >
−
O Prezo é negativo. Datos correctos?:0
+
class ArchivoBase {
−
Capacidade negativa !!!
+
    protected $handle;
−
Capacidade negativa. Datos correctos?:0
 
−
</syntaxhighlight>
 
  
−
=== Sobrecarga ===
+
    public function __construct($ruta) {
 +
        echo "Abriendo archivo...\n";
 +
        $this->handle = fopen($ruta, 'w');
 +
    }
  
−
* Dicimos que un método está sobrecargado se está definido dúas ou máis veces nunha clase e se diferenza un doutro polo número (e tipo en outras linguaxes) de argumentos.
+
    public function escribir($texto) {
 +
        fwrite($this->handle, $texto . "\n");
 +
    }
  
−
: En PHP non podemos ter sobrecarga de métodos xa que non deixar ter definidos varios métodos có mesmo nome.
+
    public function __destruct() {
−
: Un 'apaño' que podemos facer é o seguinte (parecido ao que fixemos cos construtores):
+
        echo "Cerrando archivo...\n";
 +
        fclose($this->handle);
 +
    }
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
}
−
<?php
+
</syntaxhighlight>
−
class Proba {
+
 
−
     function __call($method_name, $arguments) {
+
 
−
          $i = count($arguments);
+
: '''Clase filla:'''
−
          if (method_exists($this,$f=$method_name.$i)) {
+
::<syntaxhighlight lang="java" enclose="div" highlight="14" >
−
              call_user_func_array(array($this,$f),$arguments);
+
class Logger extends ArchivoBase {
−
          }
+
 
 +
     public function __construct($ruta) {
 +
        echo "Logger iniciado\n";
 +
        parent::__construct($ruta);
 
     }
 
     }
−
     private function metodo1($a){
+
 
−
         echo "<br />Chamada a 'metodo' cun argumento";
+
     public function log($mensaje) {
 +
         $this->escribir($mensaje);
 
     }
 
     }
−
     private function metodo2($a,$b){
+
 
−
         echo "<br />Chamada a 'metodo' con dous argumentos";;
+
     public function __destruct() {
 +
         echo "Logger destruido\n";
 +
        parent::__destruct();  
 
     }
 
     }
 
}
 
}
 +
</syntaxhighlight>
  
−
</syntaxhighlight>
+
== Polimorfismo e Sobrecarga ==
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
=== Polimorfismo ===
−
<?php
+
* Outra das propiedades da POO é o '''Polimorfismo'''.
 +
: Normalmente o polimorfismo dáse en clases que manteñan unha relación de herdanza, aínda que tamén se pode dar en outro tipo de relacións (por exemplo utilizando [https://es.wikipedia.org/wiki/Interfaz_(Java) interfaces]).
  
−
  $p1 = new Proba();
+
: Basicamente, é a capacidade que teñen as clase de definir métodos có mesmo nome e o mesmo número (e tipo en outras linguaxes) de argumentos.
 +
: Cando un obxecto chame a dito método ou use unha propiedade, saberá que método/propiedade utilizar en base a súa pertenza a un tipo de clase determinado.
  
−
  $p1->metodo(1);
+
* Vexamos un exemplo aplicado ao caso dos DiscosDuros.
−
  $p1->metodo(1,'Proba');
+
: Imaxinemos que creamos un método de nome 'comprobarDatos' que o que fai é que no caso dos DiscosDuros, mira que a capacidade teña un valor positivo e no caso dos Compoñenetes, o prezo teña un valor positivo. Devolverá 1 ou 0 dependendo do valor.
−
?>
 
−
</syntaxhighlight>
 
  
 +
: Se eu creo un obxecto da clase DiscosDuros e chamo a dito método, chamará ao definido na clase DiscosDuros por pertencer a ela. Dende a clase DiscosDuros vou poder chamar ao método da clase superior utilizando a expresión '''parent::'''.
  
−
: Dará como resultado:
+
'''Arquivo: DiscosDuros.php'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
Chamada a 'metodo' cun argumento
+
<?php
−
Chamada a 'metodo' con dous argumentos
 
−
</syntaxhighlight>
 
  
 +
class DiscosDuros extends Componentes{
  
−
* No exemplo estamos a utilizar a [http://php.net/manual/es/language.oop5.overloading.php#object.call función __call].
+
    .........
−
: Esta é unha función especial que se chama cando un obxecto chama a unha función que non estea definida. Recibe como datos o nome da función e os parámetros enviados na súa chamada.
+
    public function comprobarDatos(): bool {
 +
        if (parent::comprobarDatos()==0) return false;
 +
        if ($this->capacidade < 0) {
 +
            echo "<br />Capacidade negativa !!!<br />";
 +
            return false;
 +
        } else {
 +
            return true;
 +
        }
 +
    }
 +
}
 +
</syntaxhighlight>
  
  
−
<u>Nota:</u> Fixarse que as funcións están declaradas como 'private' para que dende a páxina que faga uso da clase non aparezan os métodos (en forma de axuda) no IDE de PHP cando tecleamos o nome do obxecto. Veremos a continuación a encapsulación.
+
'''Arquivo: Componentes.php'''
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
<?php
 +
    class Componentes {
 +
        ...................
 +
        public function comprobarDatos(): bool {
 +
            if ($this->prezo<0) {
 +
                echo "<br />Prezo negativo!!!<br />";
 +
                return false;
 +
            }
 +
            else {
 +
                return true;
 +
            }
 +
        }
  
−
== Atributos e Métodos de clase ==
+
    }
 +
</syntaxhighlight>
  
−
* Un método/atributo de clase pode ser chamado/usado sen necesidade de instanciar un obxecto.
 
−
: Chámase directamente dende o nome da clase.
 
  
−
: O concepto de clase o podemos asociar ao de variables globais nun programa tradicional.  
+
'''Arquivo: principal.php'''
−
: Se as variables dos obxectos son variables (atributos) 'locais' a cada un, é dicir, cada obxecto ten un valor propia para cada atributo da clase, nas variables de clase (estáticas) todos os obxectos teñen o mesmo valor, xa que fisicamente están apuntando á mesma dirección de memoria.
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
 
+
<?php
−
: Se un obxecto cambia o valor dun atributo de clase, se cambia para todos os obxectos.
+
            $disco1 = new DiscosDuros();
−
 
+
            $disco1->prezo=-100;
−
* Para declarar unha variable ou método de clase, debemos antepoñer a palabra reservada '''static'''.
+
            $disco1->capacidade=10;
−
: Para acceder a unha variable de clase debemos de poñer: '''Clase::'''$variableClase, sendo Clase o nome da clase.
+
            printf("O Prezo é negativo. Datos correctos?:%b",$disco1->comprobarDatos());
 +
            $disco1->prezo=100;
 +
            $disco1->capacidade=-10;
 +
            printf("Capacidade negativa. Datos correctos?:%b",$disco1->comprobarDatos());
 +
?>
 +
</syntaxhighlight>
  
−
: Vexamos un exemplo:
+
'''Saída:'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
class Clase {
+
Prezo negativo!!!
−
  static $variableStatic = 10;
+
O Prezo é negativo. Datos correctos?:0
−
}
+
Capacidade negativa !!!
−
</syntaxhighlight>  
+
Capacidade negativa. Datos correctos?:0
 +
</syntaxhighlight>
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
=== Sobrecarga ===
−
 
 
−
  echo Clase::$variableStatic;
 
  
−
</syntaxhighlight>
+
* Dicimos que un método está sobrecargado se está definido dúas ou máis veces nunha clase e se diferenza un doutro polo número (e tipo en outras linguaxes) de argumentos.
  
 +
: En PHP non podemos ter sobrecarga de métodos xa que non deixa ter definidos varios métodos có mesmo nome.
 +
: Un 'apaño' que podemos facer é o seguinte (parecido ao que fixemos cos construtores):
  
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
<?php
 +
class Proba {
 +
    function __call($method_name, $arguments) {
 +
          $i = count($arguments);
 +
          if (method_exists($this,$f=$method_name.$i)) {
 +
              call_user_func_array(array($this,$f),$arguments);
 +
          }
 +
    }
 +
    private function metodo1($a){
 +
        echo "<br />Chamada a 'metodo' cun argumento";
 +
    }
 +
    private function  metodo2($a,$b){
 +
        echo "<br />Chamada a 'metodo' con dous argumentos";;
 +
    }
 +
}
  
−
* Ao igual que os atributos, podemos crear métodos de clase.
+
</syntaxhighlight>  
−
: Para acceder dende un método (de clase ou static) a un atributo static temos que facer uso da palabra clave: '''self::'''
 
−
 
 
−
: Vexamos un exemplo:
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
class Clase {
 
−
  static $variableStatic = 10;
 
  
−
  static function metodoStatic(){
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
    echo self::$variableStatic;
+
<?php
−
  }
 
−
  function metodo(){
 
−
    echo self::$variableStatic;
 
−
  }
 
  
−
}
+
  $p1 = new Proba();
 +
 
 +
  $p1->metodo(1);
 +
  $p1->metodo(1,'Proba');
 +
?>
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="1,3" >
 
−
  Clase::metodoStatic(); // Chama ao método de clase
 
−
  $ob1 = new Clase();
 
−
  $obj1->metodo();  // Chama ao método e este accede á variable de clase.
 
  
 +
: Dará como resultado:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
Chamada a 'metodo' cun argumento
 +
Chamada a 'metodo' con dous argumentos
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
−
: Fixarse como para chamar a un método de clase usamos a forma: '''Clase::métodoClase()'''
 
  
 +
* No exemplo estamos a utilizar a [http://php.net/manual/es/language.oop5.overloading.php#object.call función __call].
 +
: Esta é unha función especial que se chama cando un obxecto chama a unha función que non estea definida. Recibe como datos o nome da función e os parámetros enviados na súa chamada.
  
−
* Vexamos agora un exemplo de aplicación no exemplo dos DiscosDuros.
 
−
: Podemos crear unha variable de clase que garde o número de discos duros/compoñentes creados.
 
−
: Cada vez que eu creo un compoñente aumentarei o número e se o destrúo (non teño ningunha referencia) diminúo o contador. Farei o mesmo para a clase DiscosDuros e ademais crearei un método de clase que me amose o número total (de todos os compoñentes) e o número de discos duros.
 
  
−
* '''Solución:'''
+
<u>Nota:</u> Fixarse que as funcións están declaradas como 'private' para que dende a páxina que faga uso da clase non aparezan os métodos (en forma de axuda) no IDE de PHP cando tecleamos o nome do obxecto. Veremos a continuación a encapsulación.
  
−
: '''Arquivo: Componentes.class.php'''
+
== Atributos e Métodos de clase ==
−
::<syntaxhighlight lang="java" line enclose="div" highlight="4,18,20-23,39" >
 
−
    <?php
 
  
−
    class Componentes {
+
* Un método/atributo de clase pode ser chamado/usado sen necesidade de instanciar un obxecto.
−
        static $numComponentes = 0;
+
: Chámase directamente dende o nome da clase.
−
       
 
−
        public $numSerie;
 
−
        public $nome;
 
−
        public $prezo;
 
−
        public $marca;
 
  
 +
: O concepto de clase o podemos asociar ao de variables globais nun programa tradicional.
 +
: Se as variables dos obxectos son variables (atributos) 'locais' a cada un, é dicir, cada obxecto ten un valor propia para cada atributo da clase, nas variables de clase (estáticas) todos os obxectos teñen o mesmo valor, xa que fisicamente están apuntando á mesma dirección de memoria.
  
−
        function __construct($numSerie,$nome,$prezo,$marca) {
+
: Se un obxecto cambia o valor dun atributo de clase, se cambia para todos os obxectos.
−
            $this->numSerie=$numSerie;
+
 
−
            $this->nome=$nome;
+
* Para declarar unha variable ou método de clase, debemos antepoñer a palabra reservada '''static'''.
−
            $this->prezo=$prezo;
+
: Para acceder a unha variable <u>dende fora da clase</u> debemos de poñer: '''Clase::'''$variableClase, sendo Clase o nome da clase.
−
            $this->marca=$marca;
 
−
           
 
−
            self::$numComponentes+=1;
 
−
        }
 
−
        static function imprimirTotal(){
 
−
       
 
−
            printf("Número de compoñentes:%s<br />",self::$numComponentes);
 
−
        }
 
  
−
   
+
: Vexamos un exemplo:
−
        public function getNumSerie(){
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
            return $this->numSerie;
+
class Clase {
−
        }
+
  static $variableStatic = 10;
−
        public function getNome(){
+
}
−
            return $this->nome;
+
</syntaxhighlight>  
−
        }
+
 
−
        public function getPrezo(){
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
            return $this->prezo;
+
 
−
        }
+
  echo Clase::$variableStatic;
−
        public function getMarca(){
 
−
            return $this->marca;
 
−
        }
 
−
        function __destruct(){
 
−
            self::$numComponentes-=1;
 
−
            echo "<br />Acabouse";
 
−
        }
 
  
−
    }
 
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
−
: '''Arquivo: DiscosDuros.class.php'''
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="5,7-12,15" >
 
−
<?php
 
  
−
class DiscosDuros extends Componentes{
 
−
    public $capacidade=1;  // en TB
 
−
    public static $numDiscosDuros=0;
 
  
−
    static function imprimirTotal(){
+
* Ao igual que os atributos, podemos crear métodos de clase.
−
        Componentes::imprimirTotal();
+
: Para acceder dende un método (de clase ou static) a un atributo static temos que facer uso da palabra clave: '''self::''' <u>cando  estamos dentro da clase</u>
−
        printf("Número de compoñentes:%s<br />",self::$numComponentes);
+
 
−
        printf("Número de discos:%s<br />",self::$numDiscosDuros);
+
: Vexamos un exemplo:
−
       
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
    }
+
class Clase {
−
    function __construct()
+
  static int $variableStatic = 10;
−
      {
+
 
−
          self::$numDiscosDuros+=1;
+
  static function metodoStatic(): void {
−
          $a = func_get_args();
+
    echo self::$variableStatic;
−
          $i = func_num_args();
+
  }
−
          if (method_exists($this,$f='__construct'.$i)) {
+
  function metodo(): void {
−
              call_user_func_array(array($this,$f),$a);
+
    echo self::$variableStatic;
−
          }
+
  }
−
      }
 
−
   
 
−
    function __construct4($numSerie, $nome, $marca,$capacidade) {
 
−
        parent::__construct($numSerie, $nome, 0, $marca);
 
−
        $this->capacidade=$capacidade;
 
−
        $this->prezo=100;
 
−
    }
 
  
−
    function __construct5($numSerie, $nome, $prezo, $marca,$capacidade) {
+
}
−
        parent::__construct($numSerie, $nome, $prezo, $marca);
+
</syntaxhighlight>  
−
        $this->capacidade=$capacidade;
 
−
    }
 
  
−
    function __destruct(){
+
::<syntaxhighlight lang="java" enclose="div" highlight="1,3" >
−
        parent::__destruct();
+
  Clase::metodoStatic(); // Chama ao método de clase
−
        self::$numDiscosDuros-=1;
+
  $ob1 = new Clase();
−
        echo "<br />Acabouse";
+
  $obj1->metodo(); // Chama ao método e este accede á variable de clase.
−
    }
 
  
−
    public function getCapacidadeKB(){
 
−
        return $this->capacidade*1024*1024;
 
−
    }
 
−
    public function getCapacidadeBytes(){
 
−
        return $this->getCapacidadeKB()*1024;
 
−
    }
 
−
 
−
}
 
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
−
: Arquivo: Principal.php''':
+
: Fixarse como para chamar a un método de clase usamos a forma: '''Clase::métodoClase()'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="8,21" >
+
 
−
        <?php
+
 
 +
* Vexamos agora un exemplo de aplicación no exemplo dos DiscosDuros.
 +
: Podemos crear unha variable de clase que garde o número de discos duros/compoñentes creados.
 +
: Cada vez que eu creo un compoñente aumentarei o número e se o destrúo (non teño ningunha referencia) diminúo o contador. Farei o mesmo para a clase DiscosDuros e ademais crearei un método de clase que me amose o número total (de todos os compoñentes) e o número de discos duros.
 +
 
 +
* '''Solución:'''
 +
 
 +
: '''Arquivo: Componentes.php'''
 +
::<syntaxhighlight lang="java" enclose="div" highlight="4,18,20-23,39" >
 +
    <?php
 +
 
 +
    class Componentes {
 +
        static int $numComponentes = 0;
 
          
 
          
−
          
+
         public string $numSerie;
−
            echo "<br />";
+
        public string $nome;
−
             echo "Primeiro disco";
+
        public float $prezo;
−
             echo "<br />";
+
        public string $marca;
−
             $disco10 = new DiscosDuros("1111A","Disco Duro","Seagete",2); // Tamén ten o da clase Compoñente
+
 
−
             echo DiscosDuros::imprimirTotal();
+
 
 +
        function __construct(string $numSerie,string $nome,float $prezo,string $marca) {
 +
             $this->numSerie=$numSerie;
 +
             $this->nome=$nome;
 +
             $this->prezo=$prezo;
 +
             $this->marca=$marca;
 
              
 
              
−
             $disco10=null;
+
             self::$numComponentes+=1;
−
            echo "<br />";
+
        }
−
            echo "Primeiro disco borrado";
+
        static function imprimirTotal(): void{
−
            echo "<br />";
+
       
−
            echo DiscosDuros::imprimirTotal();
+
             printf("Número de compoñentes:%d<br />",self::$numComponentes);
−
            $disco12 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
+
         }
−
             $disco13 = new DiscosDuros("3333B","Disco Duro",150.73,"Hitachi",6);
 
−
            $disco14 = new DiscosDuros("4444B","Disco Duro",150.73,"Hitachi",6);
 
−
            echo "<br />";
 
−
            echo "Tres novos discos";
 
−
            echo "<br />";
 
−
            echo DiscosDuros::imprimirTotal();
 
−
         ?>
 
−
</syntaxhighlight>
 
  
−
'''Facede os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Atributos_e_m.C3.A9todos_de_clase neste punto]'''.
+
   
 +
        public function getNumSerie(): string{
 +
            return $this->numSerie;
 +
        }
 +
        public function getNome(): string{
 +
            return $this->nome;
 +
        }
 +
        public function getPrezo(): float{
 +
            return $this->prezo;
 +
        }
 +
        public function getMarca(): string{
 +
            return $this->marca;
 +
        }
 +
        function __destruct(){
 +
            self::$numComponentes-=1;
 +
        }
  
−
== Constantes ==
+
    }
 +
</syntaxhighlight>
  
−
* Un pouco relacionado co punto anterior, temos as '''constantes'''.
+
: '''Arquivo: DiscosDuros.php'''
−
: Son valores fixos establecidos na definición da clase, que non se poden modificar en tempo de execución.
+
::<syntaxhighlight lang="java" enclose="div" highlight="5,10,29-34,,53-56" >
 +
<?php
  
−
* Para declarar unha constante no interior dunha clase usamos a palabra reservada '''const''' antes do nome da constante que <u>non debe levar o caracter $</u>.
+
class DiscosDuros extends Componentes{
−
: Como norma, o nome de constante debe estar en en maiúsculas para diferenciar facilmente unha constante dunha variable.
+
    public int $capacidade=1;  // en TB
−
::<syntaxhighlight lang="java" enclose="div" highlight="" >
+
    public static int $numDiscosDuros=0;
−
class Clase {
 
−
 
 
−
  const NUM_MAXIMO=1000;
 
−
}
 
−
</syntaxhighlight>
 
  
  
−
* Para acceder á constante podemos facelo como se fora un atributo estático (polo tanto, na memoria está a ocupar unha posición que é compartida por todos os obxectos, como sucede nas variables de clase). Podemos acceder directamente utilizando o nome da clase ou a través dun obxecto da forma:
+
   
−
::<syntaxhighlight lang="java" line enclose="div" highlight="3,4" >
+
    function __construct() {
−
  $a = new Clase();
+
      self::$numDiscosDuros+=1;
 +
      $args = func_get_args();
 +
      $num = func_num_args();
 +
      switch ($num) {  //ORDEN CONSTRUCTOR SUPERIOR => $numSerie,$nome,$prezo,$marca
 +
            case 3: // Enviamos 3 datos: num_serie (arg(0)), nome (arg(1)) e marca (arg(2))
 +
                parent::__construct(func_get_arg(0), func_get_arg(1), 500, func_get_arg(2));  // Enviamos un prezo por defecto en caso de non enviar o dato
 +
                $this->capacidade = 100;    // Podemos dar un valor por defecto ao dato non enviado
 +
                break;
 +
            case 4: // Enviamos 4 datos: num_serie (arg(0)), nome (arg(1)), marca (arg(2)) e capacidade (arg(3))
 +
                parent::__construct(func_get_arg(0), func_get_arg(1), 0, func_get_arg(2));  // Neste caso enviamos 0 como prezo por defecto
 +
                $this->capacidade = func_get_arg(3);
 +
                break;
 +
            case 5: // Chamamos ao constructor cun parámetro
 +
                parent::__construct(func_get_arg(0), func_get_arg(1), func_get_arg(2),func_get_arg(3));
 +
                $this->capacidade = func_get_arg(4);
 +
                break;
 +
        }
 +
    }
  
−
echo $a::NUM_MAXIMO;
+
    static function imprimirTotal(): void{
−
echo Clase::NUM_MAXIMO;
+
        Componentes::imprimirTotal();
 +
        printf("Número de compoñentes:%s<br />",self::$numComponentes);
 +
        printf("Número de discos:%s<br />",self::$numDiscosDuros);
 +
       
 +
    }
  
−
</syntaxhighlight>
+
    public function comprobarDatos(): bool{
 +
        if (!parent::comprobarDatos()) return false;
 +
        if ($this->capacidade < 0) {
 +
            echo "<br />Capacidade negativa !!!<br />";
 +
            return false;
 +
        } else {
 +
            return true;
 +
        }
 +
    }
  
−
=== Constantes predefinidas en PHP ===
+
    public function getCapacidadeKB(): float{
 +
        return $this->capacidade*1024*1024;
 +
    }
 +
    public function getCapacidadeBytes(): float{
 +
        return $this->getCapacidadeKB()*1024;
 +
    }
  
−
* Tedes [http://php.net/manual/es/language.constants.predefined.php neste enlace] algunhas constantes que vos poden servir na programación PHP.
+
    function __destruct(){
−
 
+
        parent::__destruct();
−
* De todas elas, vos pode axudar na programación en PHP (sobre todo en aloxamentos compartidos de Internet):
+
        self::$numDiscosDuros-=1;
−
:* __FILE__: Ruta completa e nome do arquivo. Usado dentro dun INCLUDE devolverá o nome do ficheiro do INCLUDE.
+
    }
−
:* __DIR__: Directorio do ficheiro. Usado dentro dun INCLUDE, devolverá o directorio do arquivo incluído.
+
   
 +
}
 +
</syntaxhighlight>
  
−
: Por que ?
+
: Arquivo: principal.php''':
−
: Se estades nun aloxamento compartido cun CMS (como o Wordpress que [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Adaptaci%C3%B3n_dunha_aplicaci%C3%B3n_web utilizamos na práctica] e queredes facer un include dun arquivo php, dando a ruta absoluta do voso aloxamento, teredes que averiguar dita ruta. Unha das formas é facendo un echo dunha das constantes anteriores dende un Post ou páxina do CMS.
+
::<syntaxhighlight lang="java" enclose="div" highlight="8,21" >
−
 
+
        <?php
−
== Encapsulación ==
+
       
−
 
+
       
−
* Outra das propiedades da POO é a '''Encapsulación'''.
+
            echo "<br />";
−
 
+
            echo "Primeiro disco";
−
: Mediante dita propiedade 'obrigamos' a que o uso dos datos e métodos se fagan de acordo ao implementado polo programador.
+
            echo "<br />";
−
: Ocúltanse (a o que vai facer uso da clase) aqueles métodos e propiedades que non vai ter que utilizar e evítase que os datos poidan ter valores non válidos.
+
            $disco10 = new DiscosDuros("1111A","Disco Duro","Seagete",2); // Tamén ten o da clase Compoñente
 +
            echo DiscosDuros::imprimirTotal();
 +
           
 +
            $disco10=null;
 +
            echo "<br />";
 +
            echo "Primeiro disco borrado";
 +
            echo "<br />";
 +
            echo DiscosDuros::imprimirTotal();
 +
            $disco12 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
 +
            $disco13 = new DiscosDuros("3333B","Disco Duro",150.73,"Hitachi",6);
 +
            $disco14 = new DiscosDuros("4444B","Disco Duro",150.73,"Hitachi",6);
 +
            echo "<br />";
 +
            echo "Tres novos discos";
 +
            echo "<br />";
 +
            echo DiscosDuros::imprimirTotal();
 +
        ?>
 +
</syntaxhighlight>
  
−
: En definitiva, a encapsulación  é un mecanismo no que organizamos os datos e métodos de tal forma que evitamos o acceso a os datos de calquera outra forma diferente á especificada. A encapsulación garante a integridade dos datos que contén un obxecto.  
+
'''Facede os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Atributos_e_m.C3.A9todos_de_clase neste punto]'''. Soamente os da sección 'Atributos e métodos de clase'.
  
−
* A encapsulación impleméntase cunha destas tres palabras clave:
+
== Constantes ==
−
:* Público(public): é o modificador por defecto, co cal se non poñemos nada enténdese que o modificador é public. Calquera pode acceder ás propiedades e métodos declarados como public.
 
−
:* Privado(private): o acceso as propiedades e métodos declarados como private están restrinxidos a clase na que foron creados.
 
−
:* Protexido(protected): unicamente poden acceder a estas propiedades e métodos a propia clase e as súas clases derivadas, é dicir, clases que sexan 'fillas' da clase onde o atributo/método estea declarado como protected.
 
  
−
: Estes modificadores van poder ser aplicados tanto a propiedades como a métodos.
+
* Un pouco relacionado co punto anterior, temos as '''constantes'''.
 +
: Son valores fixos establecidos na definición da clase, que non se poden modificar en tempo de execución.
  
−
: Vexamos un exemplo aplicado ao caso dos DiscosDuros...
+
* Para declarar unha constante no interior dunha clase usamos a palabra reservada '''const''' antes do nome da constante que <u>non debe levar o caracter $</u>.  
−
: Supoñamos que cando creo un DiscoDuro e doulle un prezo, quero que en función da capacidade aplique un desconto ou outro. Isto o fai un método que non quero que sexa 'visible' fora do código da clase.
+
: Como norma, o nome de constante debe estar en en maiúsculas para diferenciar facilmente unha constante dunha variable.
−
: Polo tanto terei que declaralo como 'private'. Como o desconto o vou poder aplicar a todos os compoñentes, o vou definir na clase Componentes, e o vou facer 'protected' para que o poida referenciar a subclase 'DiscosDuros' pero que non poida acceder directamente dende fora da clase Componentes.
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
class Clase {
  
−
'''Arquivo: Componentes.class.java'''
+
  const NUM_MAXIMO=1000;  // A partires de php 7.1 se pode poñer public ou private
−
::<syntaxhighlight lang="java" line enclose="div" highlight="9,18-20" >
+
}
−
<?php
+
</syntaxhighlight>
  
−
class Componentes {
+
* Por defecto a constante é pública se non poñemos modificador ningún (como calquera variable). Podemos establecer os modificadores de protected e private.
−
    public $numSerie;
 
−
    public $nome;
 
−
    public $prezo;
 
−
    public $marca;
 
  
−
    protected $desconto=0;
 
−
   
 
−
    function __construct($numSerie,$nome,$prezo,$marca) {
 
−
            $this->numSerie=$numSerie;
 
−
            $this->nome=$nome;
 
−
            $this->prezo=$prezo;
 
−
            $this->marca=$marca;
 
−
    }
 
−
       
 
−
    public function getDesconto(){
 
−
        return $this->desconto;
 
−
    }
 
  
−
    ......................
 
−
</syntaxhighlight>
 
  
 +
* Para acceder á constante podemos facelo como se fora un atributo estático (polo tanto, na memoria está a ocupar unha posición que é compartida por todos os obxectos, como sucede nas variables de clase). Podemos acceder directamente utilizando o nome da clase ou a través dun obxecto da forma:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="3,4" >
 +
$a = new Clase();
  
−
'''Arquivo: DiscosDuros.class.php'''
+
echo $a::NUM_MAXIMO;
−
::<syntaxhighlight lang="java" line enclose="div" highlight="10-14" >
+
echo Clase::NUM_MAXIMO;
−
<?php
 
  
−
class DiscosDuros extends Componentes{
+
</syntaxhighlight>
−
    public $capacidade=1;  // en TB
 
  
−
    function __construct($numSerie, $nome, $prezo, $marca,$capacidade) {
+
=== Constantes predefinidas en PHP ===
−
        parent::__construct($numSerie, $nome, $prezo, $marca);
 
−
        $this->capacidade=$capacidade;
 
−
       
 
−
        if($capacidade>5){
 
−
            $this->desconto=10; // Faremos un desconto dun 10%
 
−
        } else {
 
−
            $this->desconto=3;  // Faremos un desconto dun 3%
 
−
        }
 
−
    }
 
−
    ................
 
−
</syntaxhighlight>
 
  
 +
* Tedes [http://php.net/manual/es/language.constants.predefined.php neste enlace] algunhas constantes que vos poden servir na programación PHP.
  
−
'''Arquivo: Principal.php'''
+
* De todas elas, vos pode axudar na programación en PHP (sobre todo en aloxamentos compartidos de Internet):
−
::<syntaxhighlight lang="java" line enclose="div" highlight="5,10" >
+
:* __FILE__: Ruta completa e nome do arquivo. Usado dentro dun INCLUDE devolverá o nome do ficheiro do INCLUDE.
−
        <?php
+
:* __DIR__: Directorio do ficheiro. Usado dentro dun INCLUDE, devolverá o directorio do arquivo incluído.
−
 
 
−
          $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete",1); // Tamén ten o da clase Compoñente
 
−
            echo "<br />";
 
−
            printf("DISCO 1 DESCONTO %s%%",$disco1->getDesconto());
 
−
 
−
            echo "<br />";
 
−
            echo "<br />";
 
−
            $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
 
−
            printf("DISCO 2 DESCONTO %s%%",$disco2->getDesconto());
 
−
        ?>
 
  
−
</syntaxhighlight>
+
: Por que ?
 +
: Se estades nun aloxamento compartido cun CMS (como o Wordpress que [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Adaptaci%C3%B3n_dunha_aplicaci%C3%B3n_web utilizamos na práctica] e queredes facer un include dun arquivo php, dando a ruta absoluta do voso aloxamento, teredes que averiguar dita ruta. Unha das formas é facendo un echo dunha das constantes anteriores dende un Post ou páxina do CMS.
  
 +
== Encapsulación ==
  
−
: Dará como resultado:
+
* Outra das propiedades da POO é a '''Encapsulación'''.
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
DISCO 1 DESCONTO 3%
 
  
−
DISCO 2 DESCONTO 10%
+
: Mediante dita propiedade 'obrigamos' a que o uso dos datos e métodos se fagan de acordo ao implementado polo programador.
−
</syntaxhighlight>
+
: Ocúltanse (a o que vai facer uso da clase) aqueles métodos e propiedades que non vai ter que utilizar e evítase que os datos poidan ter valores non válidos.
  
 +
: En definitiva, a encapsulación  é un mecanismo no que organizamos os datos e métodos  de tal forma que evitamos o acceso a os datos de calquera outra forma diferente á especificada. A encapsulación garante a integridade dos datos que contén un obxecto.
  
−
* Fixarse como a única forma de acceder a unha variable 'private' dende o exterior de dita clase, é a través dun método (no exemplo 'getDesconto')
+
* A encapsulación impleméntase cunha destas tres palabras clave:
 +
:* Público(public): é o modificador por defecto, co cal se non poñemos nada enténdese que o modificador é public. Calquera pode acceder ás propiedades e métodos declarados como public.
 +
:* Privado(private): o acceso as propiedades e métodos declarados como private están restrinxidos a clase na que foron creados.
 +
:* Protexido(protected): unicamente poden acceder a estas propiedades e métodos a propia clase e as súas clases derivadas, é dicir, clases que sexan 'fillas' da clase onde o atributo/método estea declarado como protected.
  
 +
: Estes modificadores van poder ser aplicados tanto a propiedades como a métodos.
  
−
=== Protexendo os atributos ===
+
: Vexamos un exemplo aplicado ao caso dos DiscosDuros...
 +
: Supoñamos que cando creo un DiscoDuro e doulle un prezo, quero que en función da capacidade aplique un desconto ou outro. Isto o fai un método que non quero que sexa 'visible' fora do código da clase.
 +
: Polo tanto terei que declaralo como 'private'. Como o desconto o vou poder aplicar a todos os compoñentes, o vou definir na clase Componentes, e o vou facer 'protected' para que o poida referenciar a subclase 'DiscosDuros' pero que non poida acceder directamente dende fora da clase Componentes.
  
−
* Normalmente, na POO imos querer que as propiedades dunha clase non poidan ser accedidas directamente, xa que imos querer ter un 'control' sobre os valores asinados.
+
'''Arquivo: Componentes.java'''
−
: A forma de realizar este control é que a asignación de valores se faga a través dun método, no que comprobamos o valor a asignar. Isto xa o podemos facer no construtor, pero se queremos modificar os valores durante a execución do programa, teremos que facer que os atributos sexan privados e crear os métodos para asinar os valores.
+
::<syntaxhighlight lang="java" enclose="div" highlight="11,22-24" >
 +
<?php
 +
 
 +
class Componentes {
 +
    static int $numComponentes = 0;
 +
 
 +
    public string $numSerie;
 +
    public string $nome;
 +
    public float $prezo;
 +
    public string $marca;
 +
 
 +
    protected float $desconto=0;
 +
 
 +
    function __construct(string $numSerie, string $nome, float $prezo, string $marca) {
 +
        $this->numSerie=$numSerie;
 +
        $this->nome=$nome;
 +
        $this->prezo=$prezo;
 +
        $this->marca=$marca;
 +
 
 +
        self::$numComponentes+=1;
 +
    }
 +
 
 +
    public function getDesconto(): float{
 +
        return $this->desconto;
 +
    }
 +
 
 +
    ......................
 +
</syntaxhighlight>
  
−
: Inicialmente poderíamos facer algo parecido a isto (aplicado ao exemplo dos DiscosDuros e Componentes)
 
  
−
'''Arquivo: DiscosDuros.class.php'''
+
'''Arquivo: DiscosDuros.php'''
−
::<syntaxhighlight lang="java" line enclose="div" highlight="4,17-28" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="10-14" >
 
<?php
 
<?php
  
 
class DiscosDuros extends Componentes{
 
class DiscosDuros extends Componentes{
−
     private $capacidade=1;  // en TB
+
     public int $capacidade=1;  // en TB
  
−
     function __construct($numSerie, $nome, $prezo, $marca,$capacidade) {
+
     function __construct(string $numSerie, string $nome, float $prezo, string $marca, int $capacidade) {
 
         parent::__construct($numSerie, $nome, $prezo, $marca);
 
         parent::__construct($numSerie, $nome, $prezo, $marca);
 
         $this->capacidade=$capacidade;
 
         $this->capacidade=$capacidade;
Línea 1242: Línea 1431:
 
             $this->desconto=3;  // Faremos un desconto dun 3%
 
             $this->desconto=3;  // Faremos un desconto dun 3%
 
         }
 
         }
−
       
 
 
     }
 
     }
−
     public function cambiarCapacidade($novoValor){
+
     ................
−
        if ($novoValor<0) { // Non deixamos unha capacidade negativa
+
</syntaxhighlight>  
−
            return 0;
 
−
        }
 
−
        else {
 
−
            $this->capacidade=$novoValor;
 
−
            return 1;
 
−
        }
 
−
    }
 
−
    public function getCapacidade(){
 
−
        return $this->capacidade;
 
−
    }
 
−
   
 
  
−
</syntaxhighlight>
 
  
−
* Liña 4: Declaramos a capacidade como privada.
+
'''Arquivo: principal.php'''
−
* Liñas 17-25: Definimos un método cambiarCapacidade que vai comprobar se a capacidade é negativa. Se o é, retorna 0. En caso contrario, cambia a capacidade e retorno 1
+
::<syntaxhighlight lang="java" enclose="div" highlight="5,10" >
−
* Liñas 26-28: Definimos un método para que devolva a capacidade.
 
−
 
 
−
 
 
−
'''Arquivo: Principal.php'''
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="5,16" >
 
 
         <?php
 
         <?php
 
    
 
    
 
           $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete",1); // Tamén ten o da clase Compoñente
 
           $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete",1); // Tamén ten o da clase Compoñente
 
             echo "<br />";
 
             echo "<br />";
−
             if ($disco1->cambiarCapacidade(4)){
+
             printf("DISCO 1 DESCONTO %.2f%%",$disco1->getDesconto());
−
                echo "Capacidade cambiada <br />";
+
−
                printf("Nova capacidade Disco 1:%d",$disco1->getCapacidade());
 
−
            }
 
−
            else {
 
−
                echo "A capacidade do DISCO 1 non pode ser negativa";
 
−
            }
 
−
           
 
 
             echo "<br />";
 
             echo "<br />";
 
             echo "<br />";
 
             echo "<br />";
 
             $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
 
             $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
−
             if ($disco1->cambiarCapacidade(-2)){
+
             printf("DISCO 2 DESCONTO %.2f%%",$disco2->getDesconto());
−
                echo "Capacidade cambiada <br />";
+
        ?>
−
                printf("Nova capacidade Disco 2:%d",$disco1->getCapacidade());
+
 
−
            }
 
−
            else {
 
−
                echo "A capacidade do DISCO 2 non pode ser negativa";
 
−
            }
 
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
−
: Da como resultado:
+
 
 +
: Dará como resultado:
 
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
Capacidade cambiada
+
DISCO 1 DESCONTO 3%
−
Nova capacidade Disco 1:4
 
  
−
A capacidade do DISCO 2 non pode ser negativa
+
DISCO 2 DESCONTO 10%
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
  
−
* PHP é un pouco 'especial' e atopamos diferentes artigos no que non se recomenda o uso de métodos get e set para cada propiedade por [https://web.archive.org/web/20140625191431/https://developers.google.com/speed/articles/optimizing-php motivos de optimización de código].
+
* Fixarse como a única forma de acceder a unha variable 'private' dende o exterior de dita clase, é a través dun método (no exemplo 'getDesconto')
  
−
: Eu penso que vai depender da aplicación e de como ides necesitar modificar os valores das propiedades dunha clase.
 
−
: Se por exemplo, non ides modificar os valores e soamente ides darlles uns valores iniciais (irían no construtor, onde podedes validalos) non necesitaríamos crear un método 'set' para darlle un valor a unha propiedade e como no código non teríamos asignacións, poderíamos non ter un método 'get'.
 
−
: Se a nosa clase vai ser utilizada en outros proxectos e o uso indebido das propiedades pode dar lugar a problemas, deberíamos ter un método 'set' por cada propiedades para controlar que os valores son os correctos.
 
  
−
=== Métodos máxicos ===
+
=== Protexendo os atributos ===
  
 +
* Normalmente, na POO imos querer que as propiedades dunha clase non poidan ser accedidas directamente, xa que imos querer ter un 'control' sobre os valores asinados.
 +
: A forma de realizar este control é que a asignación de valores se faga a través dun método, no que comprobamos o valor a asignar. Isto xa o podemos facer no construtor, pero se queremos modificar os valores durante a execución do programa, teremos que facer que os atributos sexan privados e crear os métodos para asinar os valores.
  
−
* PHP incorpora dous métodos 'especiais' chamados [http://php.net/manual/es/language.oop5.magic.php máxicos] que son chamados automaticamente (parecido ao que fixemos coa función __call) cando accedemos a unha propiedade dunha clase calquera:
 
  
−
:* '''Método __get''': Se chama automaticamente cando intentamos acceder a unha propiedade calquera dunha clase. Leva como parámetro o nome do atributo do que queremos obter o valor.
+
* <u>Nota:</u> Noutras linguaxes coñecense como métodos get (obter o valor dun atributo) e métodos set(darlle un valor a un atributo).
−
: Por exemplo:
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
class Clase{
 
  
−
private $propiedade;
 
  
−
public function __get($atributo) { 
+
: Inicialmente poderíamos facer algo parecido a isto (aplicado ao exemplo dos DiscosDuros e Componentes)
−
      return $this->atributo;
 
−
} 
 
−
}
 
−
</syntaxhighlight>
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
  $obj = new Clase();
 
−
  echo $obj->propiedade;
 
−
</syntaxhighlight>
 
  
 +
'''Arquivo: DiscosDuros.php'''
 +
::<syntaxhighlight lang="java" enclose="div" highlight="4,17-28" >
 +
<?php
  
−
:* '''Método __set''': Set chámase automaticamente cando intentamos dar un valor a unha propiedade dunha clase. Ten como parámetros de entrada o nome do atributo e o valor que se lle quere dar.
+
class DiscosDuros extends Componentes{
−
: Por exemplo:
+
    private int $capacidade=1;  // en TB
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
class Clase{
 
  
−
  private $propiedade1;
+
    function __construct(string $numSerie, string $nome, float $prezo, string $marca, int $capacidade) {
−
private $propiedade2;
+
        parent::__construct($numSerie, $nome, $prezo, $marca);
 +
        $this->capacidade=$capacidade;
 +
       
 +
        if($capacidade>5){
 +
            $this->desconto=10; // Faremos un desconto dun 10%
 +
        } else {
 +
            $this->desconto=3; // Faremos un desconto dun 3%
 +
        }
 +
       
 +
    }
 +
    public function setCapacidade(int $novoValor): bool {. // Se non necesito informar podo poñer void e non facer o return
 +
        if ($novoValor<0) { // Non deixamos unha capacidade negativa
 +
            return false;
 +
        }
 +
        else {
 +
            $this->capacidade=$novoValor;
 +
            return true;
 +
        }
 +
    }
 +
    public function getCapacidade(): int{
 +
        return $this->capacidade;
 +
    }
 +
   
  
−
public function __set($atributo,$valor) { 
 
−
      $this->atributo=$valor;
 
−
  } 
 
−
}
 
−
}
 
−
</syntaxhighlight>
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
  $obj = new Clase();
 
−
  $obj->propiedade1=10;
 
−
  $obj->propiedade2=10;
 
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
 +
* Liña 4: Declaramos a capacidade como privada.
 +
* Liñas 17-25: Definimos un método cambiarCapacidade que vai comprobar se a capacidade é negativa. Se o é, retorna 0. En caso contrario, cambia a capacidade e retorno 1
 +
* Liñas 26-28: Definimos un método para que devolva a capacidade.
  
−
* Relacionado cos dous métodos anteriores temos a [http://php.net/manual/es/function.property-exists.php función property_exists]. A necesitamos utilizar para comprobar se o atributo que estamos intentar modificar ou obter o seu valor existe.
 
−
: Teremos que facer uso da constante __CLASS__, que devolve o nome da clase 'actual'.
 
−
: No caso de __get:
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="6" >
 
−
class Clase{
 
−
 
−
private $propiedade;
 
  
−
public function __get($atributo) {
+
'''Arquivo: principal.php'''
−
      if (property_exists(__CLASS__, $atributo)) {  
+
::<syntaxhighlight lang="java" enclose="div" highlight="5,16" >
−
        return $this->atributo;
+
        <?php
−
      }
+
 
−
      return NULL;
+
          $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete",1); // Tamén ten o da clase Compoñente
−
}
+
            echo "<br />";
−
}
+
            if ($disco1->setCapacidade(4)){
 +
                echo "Capacidade cambiada <br />";
 +
                printf("Nova capacidade Disco 1:%d",$disco1->getCapacidade());
 +
            }
 +
            else {
 +
                echo "A capacidade do DISCO 1 non pode ser negativa";
 +
            }
 +
           
 +
            echo "<br />";
 +
            echo "<br />";
 +
            $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
 +
            if ($disco1->setCapacidade(-2)){
 +
                echo "Capacidade cambiada <br />";
 +
                printf("Nova capacidade Disco 2:%d",$disco1->getCapacidade());
 +
            }
 +
            else {
 +
                echo "A capacidade do DISCO 2 non pode ser negativa";
 +
            }
 
</syntaxhighlight>  
 
</syntaxhighlight>  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
 
−
  $obj = new Clase();
+
: Da como resultado:
−
  echo $obj->propiedade;
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
Capacidade cambiada
 +
Nova capacidade Disco 1:4
 +
 
 +
A capacidade do DISCO 2 non pode ser negativa
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
  
−
: No caso de __set:
+
* PHP é un pouco 'especial' e atopamos diferentes artigos no que non se recomenda o uso de métodos get e set para cada propiedade por [https://web.archive.org/web/20140625191431/https://developers.google.com/speed/articles/optimizing-php motivos de optimización de código].
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
class Clase{
 
  
−
private $propiedade1;
+
: Eu penso que vai depender da aplicación e de como ides necesitar modificar os valores das propiedades dunha clase.
−
private $propiedade2;
+
: Se por exemplo, non ides modificar os valores e soamente ides darlles uns valores iniciais (irían no construtor, onde podedes validalos) non necesitaríamos crear un método 'set' para darlle un valor a unha propiedade e como no código non teríamos asignacións, poderíamos non ter un método 'get'.
 +
: Se a nosa clase vai ser utilizada en outros proxectos e o uso indebido das propiedades pode dar lugar a problemas, deberíamos ter un método 'set' por cada propiedades para controlar que os valores son os correctos.
  
−
public function __set($atributo,$valor) { 
 
−
      if (property_exists(__CLASS__, $atributo)) {
 
−
        $this->atributo=$valor;
 
−
      }
 
−
      else {
 
−
          echo "Non existe o atributo $atributo";
 
−
      }
 
−
  } 
 
−
}
 
−
}
 
−
</syntaxhighlight>
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
  $obj = new Clase();
 
−
  $obj->propiedade1=10;
 
−
  $obj->propiedade2=10;
 
−
</syntaxhighlight>
 
  
−
* O tratamento que queirades darlle cando o atributo non exista vai depender do programador. Poderíamos retornar un 0/1 como fixamos antes cos métodos que asignaban un valor a unha propiedade private.
 
−
: No exemplo aparecería un echo.
 
  
 +
<br />
  
−
'''Facer os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Encapsulaci.C3.B3n neste punto].
+
=== Métodos máxicos ===
  
−
== Funcións relacionadas coas clases e métodos ==
 
  
−
* PHP dispón de funcións que nos van permitir saber o nome da clase a que pertence un obxecto, preguntar por se unha clase está definida, saber se un método existe nunha clase,...
+
* PHP incorpora dous métodos 'especiais' chamados [http://php.net/manual/es/language.oop5.magic.php máxicos] que son chamados automaticamente (parecido ao que fixemos coa función __call) cando accedemos a unha propiedade dunha clase calquera:
  
−
* Todas estas funcións as tedes descritas [http://php.net/manual/es/ref.classobj.php neste enlace].
+
:* '''Método __get''': Se chama automaticamente cando intentamos acceder a unha propiedade calquera dunha clase. Leva como parámetro o nome do atributo do que queremos obter o valor.
 +
: Por exemplo:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
class Clase{
  
−
[[Imagen:Php_POO_Encapsulac_1.jpg|400px|center]]
+
private $propiedade;
−
<small><center>Imaxe obtida do enlace anterior</center></small>
 
  
 +
public function __get($atributo) { 
 +
      return $this->$atributo;  // Hai que poñer $atributo para que o substitúa polo seu valor, se non estariamos a intentar devolver un atributo de nome $atributo...
 +
} 
 +
}
 +
</syntaxhighlight>
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
  $obj = new Clase();
 +
  echo $obj->propiedade;
 +
</syntaxhighlight>
  
−
* Outra función relacionada coas clases e que poderemos necesitar dela é a [http://php.net/manual/es/internals2.opcodes.instanceof.php función instanceof].
 
  
−
: A súa función é comprobar se unha variable é dunha clase determinada.
+
:* '''Método __set''': Set chámase automaticamente cando intentamos dar un valor a unha propiedade dunha clase. Ten como parámetros de entrada o nome do atributo e o valor que se lle quere dar.
−
: Un código de exemplo sería o seguinte:
+
: Por exemplo:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
  $p = new Clase();
+
class Clase{
 +
 
 +
private $propiedade1;
 +
  private $propiedade2;
  
−
  if ($p instanceof Clase){
+
  public function __set($atributo,$valor) {
−
   echo "O obxecto \$p é da clase Clase";
+
      $this->$atributo=$valor;
−
}
+
   } 
 +
}
 +
}
 +
</syntaxhighlight>
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
  $obj = new Clase();
 +
  $obj->propiedade1=10;
 +
  $obj->propiedade2=10;
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
  
 +
* Relacionado cos dous métodos anteriores temos a [http://php.net/manual/es/function.property-exists.php función property_exists]. A necesitamos utilizar para comprobar se o atributo que estamos intentar modificar ou obter o seu valor existe.
 +
: Teremos que facer uso da constante __CLASS__, que devolve o nome da clase 'actual'.
 +
: No caso de __get:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="6" >
 +
class Clase{
  
−
== Operacións con obxectos ==
+
  private $propiedade;
−
 
 
−
=== Referencias ===
 
−
 
 
−
* Unha referencia en PHP vai permitir que varias variables 'apunten' fisicamente á mesma dirección de memoria, permitindo que se unha delas modifica o valor o resto das variables que fan referencia tamén verán modificado o seu valor.
 
−
 
 
−
: Para facer unha referencia a outra variable simplemente teremos que igualalas (a partires da versión PHP5):
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
  $ob1 = new Clase();
 
−
$ob1->propiedade = 5;
 
−
 
 
−
$ob2 = $ob1;
 
−
$ob2->propiedade = 10; // Agora $ob1-> propiedade vai ter de valor 10
 
  
 +
public function __get($atributo) { 
 +
      if (property_exists(__CLASS__, $atributo)) {
 +
        return $this->$atributo;
 +
      } 
 +
      return NULL;
 +
}
 +
}
 +
</syntaxhighlight>
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
  $obj = new Clase();
 +
  echo $obj->propiedade;
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
−
<u>Nota:</u> Lembrar que no caso doutro tipo de datos crearíase unha copia nova (non sería unha referencia).
 
  
 +
: No caso de __set:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
class Clase{
  
−
=== Clonar obxectos ===
+
private $propiedade1;
 +
private $propiedade2;
  
−
* Clonar un obxecto é facer unha copia exacta do mesmo, pero fisicamente estarán ocupando posicións de memoria diferentes, polo que non teremos unha referencia como no caso anterior.
+
public function __set($atributo,$valor) { 
 +
      if (property_exists(__CLASS__, $atributo)) {
 +
        $this->$atributo=$valor;
 +
      }
 +
      else {
 +
          echo "Non existe o atributo $atributo";
 +
      }
 +
  } 
 +
}
 +
}
 +
</syntaxhighlight>
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
  $obj = new Clase();
 +
  $obj->propiedade1=10;
 +
  $obj->propiedade2=10;
 +
</syntaxhighlight>
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="4" >
+
* O tratamento que queirades darlle cando o atributo non exista vai depender do programador. Poderíamos retornar un 0/1 como fixamos antes cos métodos que asignaban un valor a unha propiedade private.
−
$ob1 = new Clase();
+
: No exemplo aparecería un echo.
−
$ob1->propiedade = 5;
 
  
−
$ob2 = clone($ob1);
 
−
$ob2->propiedade = 10;  // $ob1-> propiedade mantén o seu valor a 5
 
  
−
</syntaxhighlight>
+
'''Facer os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Encapsulaci.C3.B3n neste punto].
  
 +
== Funcións relacionadas coas clases e métodos ==
  
−
=== Comparar obxectos ===
+
* PHP dispón de funcións que nos van permitir saber o nome da clase a que pertence un obxecto, preguntar por se unha clase está definida, saber se un método existe nunha clase,...
  
−
* Temos dous operadores para comparar dous obxectos:
+
* Todas estas funcións as tedes descritas [http://php.net/manual/es/ref.classobj.php neste enlace].
  
−
:* O operador de comparación simple (==): dará como resultado verdadeiro se os obxectos que se comparan son instancias da mesma clase e os seus atributos teñen os mesmos valores.
+
[[Imagen:Php_POO_Encapsulac_1.jpg|400px|center]]
−
:* O operador de identidade (===): dará como resultado verdadeiro se as variables comparadas son referencias á mesma instancia.
+
<small><center>Imaxe obtida do enlace anterior</center></small>
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
$ob1 = new Clase();
 
−
$ob1->propiedade = 5;
 
  
−
$ob2 = $ob1;
+
* Outra función relacionada coas clases e que poderemos necesitar dela é a [http://php.net/manual/es/internals2.opcodes.instanceof.php función instanceof].
−
$ob3 = clone($ob1);
 
  
−
// $ob1==$ob2 => Dará como resultado true xa que teñen os mesmos valores.
+
: A súa función é comprobar se unha variable é dunha clase determinada.
−
  // $ob1===$ob2 => Dará como resultado true xa que unha é unha referencia á outra
+
: Un código de exemplo sería o seguinte:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
  $p = new Clase();
  
−
  // $ob1==$ob3 => Dará como resultado true xa que teñen os mesmos valores.
+
  if ($p instanceof Clase){
−
  // $ob1===$ob3 => Dará como resultado false xa que unha non é referencia da outra
+
  echo "O obxecto \$p é da clase Clase";
 +
  }
 +
</syntaxhighlight>  
  
  
−
</syntaxhighlight>
 
  
−
== Métodos máxicos ==
+
== Operacións con obxectos ==
  
−
* Existen unha serie de [http://php.net/manual/es/language.oop5.magic.php método máxicos] que se poden aplicar sobre as clases.
+
=== Referencias ===
−
: Algún deles xa os vimos [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Programaci%C3%B3n_Orientada_a_obxectos#M.C3.A9todos_m.C3.A1xicos anteriormente], na encapsulación.
+
 
 +
* Unha referencia en PHP vai permitir que varias variables 'apunten' fisicamente á mesma dirección de memoria, permitindo que se unha delas modifica o valor o resto das variables que fan referencia tamén verán modificado o seu valor.
  
−
* Comentar o [http://php.net/manual/es/language.oop5.magic.php#object.tostring método __toString]: Este método devolverá un string cando se usa o obxecto coma se fose unha cadea de texto, por exemplo dentro dun echo ou dun print. <u>Debe devolver unha cadea de texto</u>.
+
: Para facer unha referencia a outra variable simplemente teremos que igualalas (a partires da versión PHP5):
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
$ob1 = new Clase();
 +
$ob1->propiedade = 5;
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="4-6" >
+
$ob2 = $ob1;
−
  class Clase {
+
$ob2->propiedade = 10;  // Agora $ob1-> propiedade vai ter de valor 10
−
    $propiedade='valor';
 
  
−
    public function __toString(){
 
−
      return 'Isto aparece nun echo:' . $this->propiedade;
 
−
    }
 
−
  }
 
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
 +
<u>Nota:</u> Lembrar que no caso doutro tipo de datos crearíase unha copia nova (non sería unha referencia).
  
−
::<syntaxhighlight lang="java" line enclose="div" highlight="3" >
 
−
$ob1 = new Clase();
 
  
−
echo $ob1;
+
=== Clonar obxectos ===
−
</syntaxhighlight>
 
  
−
: O resultado será:
+
* Clonar un obxecto é facer unha copia exacta do mesmo, pero fisicamente estarán ocupando posicións de memoria diferentes, polo que non teremos unha referencia como no caso anterior.
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
Isto aparece nun echo:valor
 
−
</syntaxhighlight>
 
  
 +
::<syntaxhighlight lang="java" enclose="div" highlight="4" >
 +
$ob1 = new Clase();
 +
$ob1->propiedade = 5;
  
−
* Este método o usaremos cando vexamos o acceso a base de datos.
+
  $ob2 = clone($ob1);
−
: Dunha consulta a unha base de datos obteremos un array de obxectos dunha clase. Normalmente teremos que visualizar o contido dese array.
+
  $ob2->propiedade = 10; // $ob1-> propiedade mantén o seu valor a 5
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
echo "<ol>";
 
−
  foreach ($arrayObxecto as $obxecto) {
 
−
  printf("<li>%s</li>",$obxecto);
 
−
  }
 
−
  echo "</ol>";
 
  
 
</syntaxhighlight>  
 
</syntaxhighlight>  
−
 
−
: O resultado será unha lista sen ordenar no que se visualizará o indicado no método __toString da clase á que pertence $obxecto.
 
  
  
 +
=== Comparar obxectos ===
  
−
== Clases abstractas ==
+
* Temos dous operadores para comparar dous obxectos:
  
−
* A partires de PHP5 introducíronse na linguaxe as clases e os métodos abstractos.
+
:* O operador de comparación simple (==): dará como resultado verdadeiro se os obxectos que se comparan son instancias da mesma clase e os seus atributos teñen os mesmos valores.
 +
:* O operador de identidade (===): dará como resultado verdadeiro se as variables comparadas son referencias á mesma instancia.
  
−
: Para que unha clase sexa abstracta debe levar a palabra clave abstract.
+
::<syntaxhighlight lang="java" enclose="div" highlight="" >
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
$ob1 = new Clase();
−
abstract class Clase {
+
$ob1->propiedade = 5;
  
−
}
+
$ob2 = $ob1;
−
</syntaxhighlight>
+
  $ob3 = clone($ob1);
−
   
 
−
* As clases abstractas teñen estas características:
 
−
:* Non se poden crear obxectos a partir delas, isto é: unha clase abtracta non pode ser instanciada.
 
−
:* Unha clase abstracta pode incorporar métodos abstractos, que son aqueles dos que so existe a súa declaración, deixando a implementación para as clases fillas ou derivadas.
 
−
:* Unha clase abstracta pode incorporar métodos non abstractos.
 
  
−
* Para que se utilizan ?
+
// $ob1==$ob2 => Dará como resultado true xa que teñen os mesmos valores.
−
: Normalmente ides necesitar crealas cando queirades ter unha clase que sexa 'base' doutras e 'obrigar' a implementar certos métodos.
+
// $ob1===$ob2 => Dará como resultado true xa que unha é unha referencia á outra
  
−
: Por exemplo, imaxinade que estades a facer unha aplicación no que queredes modelizar as figuras xeométricas.
+
// $ob1==$ob3 => Dará como resultado true xa que teñen os mesmos valores.
−
: Así, tedes a figura Cadrado, Circulo, coas súas propiedades.
+
// $ob1===$ob3 => Dará como resultado false xa que unha non é referencia da outra
  
−
: Eu como deseñador quere que todas esas clases implementen o procedemento debuxar (que é diferentes para cada unha delas).
 
−
: Faría isto:
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
abstract class FiguraXeometrica {
 
  
−
  abstract public function debuxar();
 
−
 
−
}
 
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
−
: Agora, calquera clase que derive de FiguraXeometrica terá que implementar a método debuxar '''obrigatoriamente'''.
+
== Métodos máxicos ==
  
−
== Interfaces ==
+
* Existen unha serie de [http://php.net/manual/es/language.oop5.magic.php método máxicos] que se poden aplicar sobre as clases.
 +
: Algún deles xa os vimos [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Programaci%C3%B3n_Orientada_a_obxectos#M.C3.A9todos_m.C3.A1xicos anteriormente], na encapsulación.
  
−
== Espazos de nomes ==
+
* Comentar o [http://php.net/manual/es/language.oop5.magic.php#object.tostring método __toString]: Este método devolverá un string cando se usa o obxecto coma se fose unha cadea de texto, por exemplo dentro dun echo ou dun print. <u>Debe devolver unha cadea de texto</u>.
 +
 
 +
::<syntaxhighlight lang="java" enclose="div" highlight="4-6" >
 +
  class Clase {
 +
    $propiedade='valor';
 +
 
 +
    public function __toString(){
 +
      return 'Isto aparece nun echo:' . $this->propiedade;
 +
    }
 +
  }
 +
</syntaxhighlight>
 +
 
 +
 
 +
::<syntaxhighlight lang="java" enclose="div" highlight="3" >
 +
$ob1 = new Clase();
 +
 
 +
echo $ob1;
 +
</syntaxhighlight>
  
 +
: O resultado será:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
Isto aparece nun echo:valor
 +
</syntaxhighlight>
 +
 +
 +
* Este método o usaremos cando vexamos o acceso a base de datos.
 +
: Dunha consulta a unha base de datos obteremos un array de obxectos dunha clase. Normalmente teremos que visualizar o contido dese array.
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
echo "<ol>";
 +
foreach ($arrayObxecto as $obxecto) {
 +
  printf("<li>%s</li>",$obxecto);
 +
}
 +
echo "</ol>";
 +
 +
</syntaxhighlight>
 +
 +
: O resultado será unha lista sen ordenar no que se visualizará o indicado no método __toString da clase á que pertence $obxecto.
 +
 +
 +
 +
'''Facer os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Instanceof neste punto].'''
 +
 +
== Clases abstractas ==
 +
 +
* A partires de PHP5 introducíronse na linguaxe as clases e os métodos abstractos. 
 +
 +
: Para que unha clase sexa abstracta debe levar a palabra clave abstract.
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
abstract class Clase {
 +
 +
}
 +
</syntaxhighlight>
 +
 +
* As clases abstractas teñen estas características:
 +
:* Non se poden crear obxectos a partir delas, isto é: unha clase abtracta non pode ser instanciada.
 +
:* Unha clase abstracta pode incorporar métodos abstractos, que son aqueles dos que so existe a súa declaración, deixando a implementación para as clases fillas ou derivadas.
 +
:* Unha clase abstracta pode incorporar métodos non abstractos.
 +
 +
* Para que se utilizan ?
 +
: Normalmente ides necesitar crealas cando queirades ter unha clase que sexa 'base' doutras e 'obrigar' a implementar certos métodos.
 +
 +
: Por exemplo, imaxinade que estades a facer unha aplicación no que queredes modelizar as figuras xeométricas.
 +
: Así, tedes a figura Cadrado, Circulo, coas súas propiedades.
 +
 +
: Eu como deseñador quere que todas esas clases implementen o procedemento debuxar (que é diferentes para cada unha delas).
 +
: Faría isto:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
abstract class FiguraXeometrica {
 +
 +
  abstract public function debuxar();
 +
 +
}
 +
</syntaxhighlight>
 +
 +
: Agora, calquera clase que derive de FiguraXeometrica terá que implementar a método debuxar '''obrigatoriamente'''.
 +
 +
 +
* <u>'''Nota:'''</u>Unha clase abstracta pode ter propiedades e métodos con código que serán herdadas polas subclases.
 +
 +
 +
 +
 +
'''Facer os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Clases_abstractas neste punto].'''
 +
 +
== Interfaces ==
 +
 +
* As interfaces son un tipo especial de clases que se caracterizan en que soamente levan as definicións de métodos, pero sen ningunha implementación.
 +
 +
: Cando outra clase queira facer uso da interface terá que '''obrigatoriamente''' implementar o código dos métodos que están definidos na interface.
 +
: As interfaces, ao igual que as clases abstractas non poden ser instanciadas.
 +
: As interfaces, ao igual que as clases abstractcas poden empregar a herdanza </u>con outras interfaces</u>
 +
 +
 +
* O concepto é parecido ao das clases abstractas, pero ten dúas diferenzas importantes:
 +
:* Para utilizar unha interface non teño que herdar de dita clase, se non que simplemente incorpora a interface (con todos os seus métodos) á miña clase.
 +
:: Unha clase vai poder utilizar unha ou varias interfaces. Se empregásemos as clases abstractas soamente podemos herdar dunha.
 +
:* Unha interface non pode ter código nos métodos que <u>deben ser públicos</u> e soamente permite definir constantes, non se poden empregar atributos. É obrigatorio poñer código aos métodos nas clases que implementen a interface.
 +
 +
 +
: Como se declara ? Utilizando a palabra clave '''interface''':
 +
::<syntaxhighlight lang="java" enclose="div" highlight="1" >
 +
interface ClaseInterface {
 +
  public function metodo1(): int;  // É un exemplo de tipo de dato devolto. Se queremos que poida devolver calquera tipo, non poñer nada
 +
  public function metodo2(): string;
 +
}
 +
</syntaxhighlight>
 +
: Como vemos os métodos non levan código.
 +
 +
 +
: Para utilizar dita interface, deberemos utilizar a palabra clave '''implements''':
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
class Clase implements ClaseInterface {
 +
 +
  public function metodo1(): int {
 +
    ....
 +
  }
 +
  public function metodo2(): string {
 +
    ....
 +
  }
 +
 +
}
 +
</syntaxhighlight>
 +
 +
: Podemos combinar varias interfaces da forma:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="1" >
 +
class Clase implements ClaseInterface1,ClaseInterface2 {
 +
 +
  public function metodo1(): int {
 +
    ....
 +
  }
 +
  public function metodo2(): string {
 +
    ....
 +
  }
 +
  public function metodo3(): string {
 +
    ....
 +
  }
 +
 +
}
 +
</syntaxhighlight>
 +
 +
 +
: As interfaces tamén se poden utilizar con clases fillas:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="1" >
 +
class Clase extends ClasePai implements ClaseInterface1,ClaseInterface2 {
 +
 +
  public function metodo1(): int {
 +
    ....
 +
  }
 +
  public function metodo2(): string {
 +
    ....
 +
  }
 +
  public function metodo3(): string {
 +
    ....
 +
  }
 +
 +
}
 +
</syntaxhighlight>
 +
 +
 +
* As interfaces van permitir definir métodos cun nome específico e cun número de parámetros determinado.
 +
: Así, se por exemplo, teño unha tenda no que teñamos diferentes tipos de produtos formando listas. Cada lista estará formada por un tipo de produto determinado, e eu quero que aquelas que o necesiten, poidan buscar un produto da súa lista. A implementación da busca será diferente por cada tipo de produto. Podo crear unha interface, de tal forma que para buscar sempre vou mandar un único parámetro como dato a utilizar na busca. Calquera clase que necesite buscar terá que incorporar a miña interface e terá que implementar o código específico, pero obrigatoriamente terá que levar o nome do procedemento indicando por min e o parámetro indicado por min na interface:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
interface Busca {
 +
 +
  public function buscaProduto(int $valor): string ;
 +
 +
}
 +
</syntaxhighlight>
 +
 +
== Namespaces ==
 +
 +
 +
* Información obtida da [http://php.net/manual/es/language.namespaces.php web php.net].
 +
 +
 +
* Os espazos de nomes proporcionan unha maneira de agrupar clases, interfaces, funcións e constantes relacionadas.
 +
 +
: Tamén vai servir para solucionar o problema de que utilicemos clases ou código de terceiros (desenvolvido por outras persoas) no que pode darse o caso de que se chamen igual varias clases, constantes, funcións,..., polo que teríamos un erro ao intentar utilizalas.
 +
 +
* Tamén van poder utilizarse para abreviar nomes extra-largos que poidamos ter nos nomes de clases, mellorando a lexibilidade do código fonte.
 +
 +
 +
* Calquera código PHP pode estar dentro dun namespace (espazo de nome) pero soamente vense afectado o seguinte tipo de código: clases (incluíndo abstractas e traits), interfaces, funcións e constantes.
 +
 +
=== Declaración ===
 +
 +
* Os espazos de nomes decláranse utilizando a palabra reservada '''namespace'''.
 +
: Un ficheiro que conteña un espazo de nomes debe declaralo ao comezo do mesmo, <u>antes que calquera outro código ou espazo en branco</u>, cunha excepción: a palabra reservada [http://php.net/manual/es/control-structures.declare.php declare].
 +
 +
 +
::<syntaxhighlight lang="java" enclose="div" highlight="2" >
 +
<?php
 +
namespace MiProyecto;
 +
 +
const CONSTANTE_1 = 1;
 +
class Clase { /* ... */ }
 +
function funcion_1() { /* ... */ }
 +
 +
 +
</syntaxhighlight>
 +
 +
<u>Nota:</u> Nos exemplos estamos a utilizar clases, pero lembrar, como está indicado ao principio, que poderíamos ter funcións, constantes...
 +
 +
 +
* Pódese definir o mesmo espazo de nomes en varios ficheiros, permitindo a separación do contido dun espazo de nomes a través do sistema de ficheiros.
 +
 +
: Por exemplo:
 +
'''Arquivo físico:''' Arquivo1.php
 +
::<syntaxhighlight lang="java" enclose="div" highlight="2" >
 +
<?php
 +
namespace MiProyecto;
 +
 +
const CONSTANTE_1 = 1;
 +
class Clase1 { /* ... */ }
 +
function funcion_1() { /* ... */ }
 +
 +
</syntaxhighlight>
 +
 +
'''Arquivo físico:''' Arquivo2.php
 +
::<syntaxhighlight lang="java" enclose="div" highlight="2" >
 +
<?php
 +
namespace MiProyecto;
 +
 +
const CONSTANTE_2 = 1;
 +
class Clase2 { /* ... */ }
 +
function funcion_2() { /* ... */ }
 +
 +
</syntaxhighlight>
 +
 +
 +
* Un espazo de nome o podemos identificar cun cartafol nun sistema de arquivos. En diferentes cartafoles podemos ter o mesmo nome de arquivo. Para referenciar a un arquivo teremos que antepoñer o nome do cartafol (ruta relativa/absoluta) ao nome do arquivo.
 +
 +
* '''Aínda que non é obrigatorio, <u>crearemos un cartafol por cada un dos namespaces</u>.'''
 +
: Por exemplo, se teño unha clase MiClase dentro do namespace 'experimento', creamores un cartafol de nome experimento e dentro del poñeremos a clase miclase.php.
 +
 +
=== Uso ===
 +
 +
* Para referenciar a unha clase que se atopa definida nun espazo de nome de nome 'Espazo' teremos que poñer:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
obj = new Espazo\Clase();
 +
</syntaxhighlight>
 +
 +
: Sendo Clase unha clase definida no espazo de nomes 'Espazo' da forma:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
<?php
 +
namespace Espazo;
 +
class Clase {
 +
  ...............
 +
}
 +
</syntaxhighlight>
 +
 +
 +
: Imaxinemos que no caso da clase Componentes, o noso sitio tamén xestiona compoñentes dos coches. Tamén teremos definida unha clase Componentes no que gardaremos:
 +
 +
'''Arquivo: <u>Coches/</u>Componentes.php'''
 +
::<syntaxhighlight lang="java" enclose="div" highlight="2" >
 +
<?php
 +
namespace ClasesCoches;
 +
 +
class Componentes {
 +
   
 +
    public float $prezo;
 +
    public string $modelo;
 +
    public int $ano_comercializacion;
 +
   
 +
}
 +
</syntaxhighlight>
 +
 +
: Fixarse que, como estamos a dar un nome ao arquivo físico igual ao nome da clase, non van poder estar fisicamente no mesmo cartafol, por iso creamos un cartafol de nome /Coches/ onde estarán todas as clases que teñan que ver cos compoñentes dos coches.
 +
 +
'''Arquivo: <u>Informatica/</u>Componentes.php'''
 +
::<syntaxhighlight lang="java" enclose="div" highlight="2" >
 +
<?php
 +
namespace ClasesInformatica;
 +
class Componentes {
 +
  public string $numSerie;
 +
  public string $nome;
 +
  public float $prezo;
 +
  public string $marca;
 +
}
 +
</syntaxhighlight>
 +
 +
: O mesmo facemos coas clases que teñan que ver con compoñentes informáticos, e creamos un cartafol de nome /Informatica/ onde gardaremos as clases dos compoñentes informáticos.
 +
 +
 +
* Como vemos, creamos un espazo de nome 'ClasesInformatica' e outro 'ClasesCoches'.
 +
 +
* Para poder utilizar ditas clases, teremos que referencialas polo seu espazo de nome, xa que a clase Componentes podería facer referencia tanto a clase gardada no espazo de nomes ClasesInformatica ou a clase gardada no espazo de nome ClasesCoches:
 +
 +
 +
'''Arquivo: Principal.php'''
 +
::<syntaxhighlight lang="java" enclose="div" highlight="5,6,17,18" >
 +
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
<?php
 +
 +
  require ('Coches/Componentes.php');
 +
  require ('Informatica/Componentes.php');
 +
 
 +
?>
 +
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
 +
    <head>
 +
        <meta charset="utf-8" />
 +
        <title>Exemplos de códigos php</title>
 +
    </head>
 +
    <body>
 +
 +
    <?php 
 +
        $objCoche1 = new ClasesCoches\Componentes();
 +
        $objInfor1 = new ClasesInformatica\Componentes();
 +
    ?>
 +
    </body>   
 +
</html>
 +
</syntaxhighlight>
 +
 +
* Liñas 5-6: Incluímos os arquivos físicos onde están definidas as clases.
 +
* Liñas 17-18: Creamos un obxecto de cada clase. Fixarse como están referenciadas as clases de cada espazo de nome.
 +
 +
 +
 +
<br />
 +
* <u>'''Nota:'''</u> Normalmente o que se fai cando se van empregar clases que están noutro espazo de nome é empregar '''use''' despois do require, da forma: use name_space\nome_clase;
 +
 +
=== Sub-espazos ===
 +
 +
* Ao concepto aprendido no punto anterior podemos sumarlle o concepto de sub-espazo, que é cando temos unha clase que está definida non espazo de nomes dentro doutro espazo de nomes. Sería como un cartafol dentro dun cartafol no sistema de arquivos.
 +
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
<?php
 +
namespace MiñasClases\OutrasClases;
 +
class Clase {
 +
 +
}
 +
</syntaxhighlight>
 +
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
<?php
 +
  $obj1 = new Miñasclases\OutrasClases\Clase();
 +
 +
</syntaxhighlight>
 +
 +
 +
: No exemplo dos compoñentes, poderíamos ter un espazo para as clases que teñan relación cos Computadores, outro espazo para os Móbiles,... Fixarse que fisicamente poden estar no mesmo cartafol (/Informatica/) mentres non teñan nomes iguais.
 +
 +
* '''Aínda que non é obrigatorio, <u>crearemos un cartafol por cada un dos namespaces e subespazos</u>.'''
 +
: Por exemplo, se teño unha clase MiClase dentro do namespace 'experimento', creamores un cartafol de nome experimento e dentro del poñeremos a clase miclase.php.
 +
 +
 +
<br />
 +
=== Alias ===
 +
 +
* Se creamos unha estrutura de espazos de nomes moi grande, pode darse o caso de que para referenciar a unha clase teñamos que poñer algo parecido a isto:
 +
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
<?php
 +
  $obj1 = new Miñasclases\OutrasClases\Outras\MaisClases\Clase();
 +
 +
</syntaxhighlight>
 +
 +
: Para evitalos podemos facer uso dos '''alias'''. Un alias é un nome que fai referencia a un conxunto de espazos de nomes.
 +
: Así,
 +
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 +
<?php
 +
namespace Espazo\SubEspazo1\SubEspazo2\SubEspazo3;
 +
class Clase {
 +
 +
}
 +
</syntaxhighlight>
 +
 +
: Agora, para referenciar a clase creo un alias do seu espazo de nome:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="4,6" >
 +
<?php
 +
  require ('Clase.php');
 +
 +
  use Espazo\SubEspazo1\SubEspazo2\SubEspazo3 as EspazoSub;
 +
 +
  $ob1 = new EspazoSub\Clase();
 +
?>
 +
</syntaxhighlight>
 +
 +
* Liña 4: Creamos un alias de nome 'EspazoSub' que é equivalente a poñer Espazo\SubEspazo1\SubEspazo2\SubEspazo3.
 +
* Liña 5: Facemos referencia á clase Clase por medio do alias.
 +
 +
 +
<u>Nota:</u> Se non poñemos o 'as EspazoSub' collerá como alias a última parte do use. No exemplo sería SubEspazo3.
 +
 +
 +
 +
<br />
 +
=== Referenciando outros namespaces ===
 +
 +
Imaxinemos que temos a Clase1 dentro do espazo Espazo1 e a clase Clase2 dentro do espazo Espazo2,
 +
 +
* Se temos varios espazos diferentes y queremos referenciar a clases definidas noutros espazos teríamos que:
 +
:* Ter un require/include da clase que imos a empregar. Lembrar que isto é o lugar físico onde se atopa o arquivo PHP.
 +
:* '''Facer o use da forma:''' use Espazo\Clase;
 +
 +
No exemplo anterior, se Clase1 emprega a Clase2 tería:
 +
 +
::<syntaxhighlight lang="java" enclose="div" highlight="3,5,8" >
 +
<?php
 +
 +
  namespace Espazo1;
 +
 +
  require ('Clase2.php');
 +
  use Espazo2\Clase2;
 +
 +
  class Clase1 {
 +
        ...........
 +
        $clase2 = new Clase2();
 +
  }
 +
 +
?>
 +
</syntaxhighlight>
 +
 +
 +
 +
<br />
 +
'''<u>IMPORTANTE:</u>''' Cando dentro dun namespaces facemos unha referencia a unha clase e queremos acceder a unha clase global da linguaxe (por exemplo, as clases mysqli para traballar contra bases de datos) non as va a atopar, xa que ao definir un namespace vai buscar as clases que se atopan dentro do mesmo.
 +
 +
No exemplo anterior:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="11" >
 +
<?php
 +
 +
  namespace Espazo1;
 +
 +
  require ('Clase2.php');
 +
  use Espazo2\Clase2;
 +
 +
  class Clase1 {
 +
        ...........
 +
        $clase2 = new Clase2();
 +
        $conexion = new mysqli("host", "usuario", "contraseña", "base_de_datos");  // NON A VAI ATOPAR
 +
  }
 +
 +
?>
 +
</syntaxhighlight>
 +
 +
 +
: Para solucionalo temos dúas opcións:
 +
:* Empregar o operador de resolución de ámbito global: Isto é, poñer \ antes do clase a empregar. Por exemplo: $conexion = new '''\'''mysqli("host", "usuario", "contraseña", "base_de_datos");
 +
:* Declarar use ao principio do arquivo:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="4" >
 +
::<?php
 +
 +
  namespace Espazo1;
 +
  use mysqli;
 +
 +
  require ('Clase2.php');
 +
  use Espazo2\Clase2;
 +
 +
  class Clase1 {
 +
        ...........
 +
        $clase2 = new Clase2();
 +
        $conexion = new mysqli("host", "usuario", "contraseña", "base_de_datos");  // AGORA SI A VAI ATOPAR
 +
  }
 +
 +
?>
 +
</syntaxhighlight>
 +
 +
 +
 +
 +
 +
<br />
 +
'''Facer os exercicios indicados [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Exercicios_POO#Namespaces neste punto]'''
 +
 +
 +
 +
<br />
 +
 +
== Documentación ==
 +
 +
* Para documentar código PHP existe un estándard parecido a Java (javadoc) coñecido como [https://www.phpdoc.org/ PHPDOC].
 +
: Proporciona unha forma coherente de documentar clases, métodos, propiedades, constantes e máis en PHP.
 +
 +
 +
* Características Principais de PHPDoc:
 +
 +
:* '''Comentarios de Documentación:''' Utiliza comentarios de varias liñas comezando con /** e terminando con */ para documentar elementos do código.
 +
:* '''Etiquetas:''' PHPDoc utiliza etiquetas especiais que comezan con @, como @param, @return, @throws, @var, etc., para proporcionar información específica.
 +
:* '''Descricións:''' Permite engadir descricións lexibles para clases, métodos, parámetros e valores de retorno.
 +
:* '''Compatibilidade con Ferramentas''': Moitas ferramentas e IDEs como PhpStorm, Visual Studio Code e outros, recoñecen e utilizan os comentarios de PHPDoc para proporcionar intellisense, comprobación de tipos e outras funcionalidades.
 +
 +
 +
 +
* Exemplo de Uso de PHPDoc:
 +
::<syntaxhighlight lang="java" enclose="div" highlight="4" >
 +
<?php
 +
 +
/**
 +
* Clase para representar un Libro.
 +
*
 +
* @package MiProyecto\Modelo
 +
*/
 +
class Libro {
 +
 +
    /**
 +
    * Título do libro.
 +
    *
 +
    * @var string
 +
    */
 +
    protected string $titulo;
 +
 +
    /**
 +
    * Asigna o título do libro.
 +
    *
 +
    * @param string $titulo Título do libro.
 +
    * @return void
 +
    */
 +
    public function setTitulo(string $titulo): void {
 +
        $this->titulo = $titulo;
 +
    }
 +
 +
    /**
 +
    * Obten o título do libro.
 +
    *
 +
    * @return string Título do libro.
 +
    */
 +
    public function getTitulo(): string {
 +
        return $this->titulo;
 +
    }
 +
}
 +
</syntaxhighlight>
  
 +
* Neste exemplo, cada elemento importante da clase Libro está documentado usando comentarios de PHPDoc.
 +
* Beneficios de Usar PHPDoc:
 +
:* '''Mellora a Lexibilidade''': Fai que o código sexa máis fácil de entender para outros desenvolvedores.
 +
:* '''Soporte para Xeración de Documentación Automática''': Ferramentas como phpDocumentor poden xerar documentación do código automaticamente baseándose nestes comentarios.
 +
:* '''Axuda no Desenvolvemento''': IDEs modernos utilizan PHPDoc para proporcionar autocompletado, verificación de tipos e axuda contextual.
  
  
 +
* PHPDoc é esencial para manter un código PHP grande e complexo ben documentado, lexible e fácil de manter.
  
  
  
−
<br> -- [[Usuario:angelfg|Ángel D. Fernández González]] -- (2016).
+
<br />
 +
<br> -- [[Usuario:angelfg|Ángel D. Fernández González]] -- (2025).

Revisión actual del 09:38 19 mar 2026

Introdución

  • Na actualidade empréganse fundamentalmente dúas formas de programación:
  • Programación estruturada
  • Programación orientada a obxectos.
  • A programación estruturada baséase na utilización de 3 estruturas básicas: Secuencial, Condicional e Repetitiva.
En base a estas 3 estruturas podemos 'programar' calquera solución informática.
É un tipo de programación 'orientada' ao procedemento. Programamos pensando nos procesos que imos que ter que aplicar aos datos dos que dispoñemos, para que en base a unha entrada produzamos unha saída.
Vexamos un exemplo.
Imaxinemos que queremos programar unha solución informática para xestionar as contas bancarias.
Partimos de que temos uns datos: un número de conta, un saldo, un titular, unha dirección.
Creamos un programa no que definimos globalmente os datos, por exemplo en forma de array, no que cada elemento do array vai ser unha conta cos datos anteriores. Podemos ler ditos datos dende unha base de datos un dun arquivo.
Isto o faríamos en primeiro lugar utilizando unha estrutura secuencial.
Creamos os procedementos necesarios para tratar ditos datos, pensando no tratamentos que imos dar a ditos datos:
Procedemento de ingresarCartos, ao que mandaríamos como parámetro un número de conta e uns cartos. Buscaríamos dito número de conta no array e aumentaríamos o seus ingresos.
Procedemento de retirarCartos, ao que mandaríamos como parámetro un número de conta e uns cartos. Buscaríamos dito número de conta no array e diminuímos o seus ingresos.
....


  • A programación orientada a obxectos, denominada POO, basease no uso de clases e obxectos (instancias de clase) para dar unha solución informática a un problema.
É un tipo de programación 'orientada' ao dato. Programamos pensando na información que dispoñemos e 'modelizamos' ditos datos con clases.
Unha clase vai estar formada por 'variables' ('atributos na POO') e 'procedementos' ('métodos na POO') para tratar os datos gardados nas variables. Se temos unha fábrica de galletas, a clase Galleta sería o molde da galleta. Có molde podemos crear todas as galletas, pero o molde non é ningunha galleta en particular.
O obxecto dunha clase (denominado instancia de clase) ven ser cada un dos datos que queremos gardar na nosa solución informática. Dentro do mesmo código temos os valores que queremos gardar e os métodos que van poder tratar ditos valores. O conxunto dos valores que temos nun obxecto nun momento determinado denomínase estado do obxecto. Seguindo o exemplo da fábrica de galletas, cada obxecto (instancia de clase) ven ser unha galleta.
Na POO obtemos un código máis lexible e reutilizable.
A POO é máis achegada a nosa forma de pensar. Podemos ver calquera cousa do que nos rodea e abstraer as súas propiedades para formar na nosa cabeza a idea de clase.
Así, se vemos un coche podemos abstraer as propiedades de cor, potencia, modelo,...! Acabamos de crear unha clase !. Para esas propiedades podemos crear múltiples instancias (obxectos) que van representar coches diferentes, cada un cuns valores diferentes (estado).
Seguindo o exemplo anterior das contas bancarias...
  • Creamos unha clase ContaBancaria que teña as seguintes variables (atributos ou propiedades) e procedementos (métodos):
  • Atributos: Número de conta, titular, saldo,...
Métodos:
ingresarCartos
retirarCartos
Ditos métodos non necesitan levar parámetros xa que van tratar os datos que se atopan definidos na mesma clase.
É dicir, se eu creo un obxecto desta clase, por exemplo:
conta1 => NumConta: 1111, Titular: 'Angel', Saldo: 4000
Os métodos que se atopan definidos na clase poden ser utilizados polo obxecto conta1. Ditos métodos van poder acceder aos datos da clase (número de conta e saldo).
  • Creamos unha clase Banco, formado por, entre outros atributos, un array de obxectos ContaBancaria. Ese array gardaría todas as contas bancarias dun banco.


  • En conclusión:
  • Na programación estruturado os datos e os procedementos están separados e sen relación.
  • Búscase o procesamento duns datos de entrada para obter unha saída.
  • A idea e buscar unha solución informática a un problema pensando no uso de procedementos e funcións como guía.
  • Na POO se ten como guía aos datos.
  • Primeiro defínense as clases (datos) e despois implantase os métodos (procedementos) que van facer uso destes datos.

Creando clases

  • Unha clase é un molde do que despois poderemos crear obxectos.
  • As variables que están definidas dentro dunha clase reciben o nome de atributos ou propiedades e as funcións que están definidas dentro dunha clase reciben o nome de métodos. Os métodos da clase son usados para manipular as súas propias propiedades.


  • As clases defínense empreñando a palabra clave class seguida do nome da clase e dun bloque de código entre chaves. A sintaxe é a seguinte:
<?php
class SimpleClass
{
    // propiedade
    public string $var = 'valor por defecto';

    // métodos
    public function amosarVar() {
        echo $this->var;
    }
}
?>


  • O nome da clase pode comezar por unha letra ou guión baixo seguido de letras, números e guións baixos. Non se pode utilizar ningunha palabra reservada de PHP.
  • Como norma, o nome dunha clase comezará cunha letra maiúscula.
Exemplos:
class Pelota {}
class ContaBancaria {}


  • Cada clase, aínda que non é obrigatorio, a definiremos nun arquivo php separado que levará o seu nome.
Así, por exemplo, a clase Alumno terá un arquivo de nome Alumno.php
Como norma, a extensión dunha clase será:
  • Se seguimos as recomendacións de PHP Standards Recommendations soamente será necesario a extensión php. No exemplo anterior sería Alumno.php. Esta opción es la empleada por los Framweworks de PHP para la carga automática de clases.


Se dentro dunha páxina php necesito utilizar a clase Alumno terei que poñer:
<?php
   require_once('Alumno.php');
?>
Nota: Lembrar as formas que vimos para incluír arquivos externos.
No exemplo estamos a supoñer que o arquivo 'Alumno.php' atópase no mesmo sitio que a clase php que está a facer uso del.


  • Vexamos un exemplo de clase:
Arquivo: DiscosDuros.php
<?php

class DiscosDuros {
    public string  $numSerie;
    public string $marca;
    public int $capacidade=1;   // en TB
    
    public function getCapacidadeKB(){
        return $this->capacidade*1024*1024;
    }
}
Como vemos, temos definidos tres atributos, número de serie,marca e capacidade. Por defecto, a capacidade de todos os obxectos que cremos desta clase será de 1TB.
Tamén vemos a definición dun método (getCapacidadeKB) que devolve a capacidade do disco en KB. Dentro deste método sinalar o uso da variable $this.

Nota: Veremos máis adiante o significado do modificador 'public'.

Variable $this

  • En todas as linguaxe de POO sempre imos ter unha forma de referenciar a 'instancia' actual dentro do código da clase.
Que significa a 'instancia actual' ?
  • Cando cremos obxectos dunha clase, cada obxecto terá os seus datos.
Así, podo crear dúas contas bancarias (dous obxectos):
conta1 => NumConta: 1111, Titular: 'Angel', Saldo: 4000
conta2 => NumConta: 2222, Titular: 'Pepe', Saldo: 2000
Agora, cada obxecto vai poder chamar aos métodos definidos na clase.
Así:
O obxecto conta1 vai poder chamar ao método conta1.devolverSaldo(), o cal, fai un return do saldo (debería devolver 4000)
O obxecto conta2 vai poder chamar ao método conta2.devolverSaldo(), o cal, fai un return do saldo (debería devolver 2000)
Como vemos cada obxecto ten uns datos diferentes pero os dous chaman o mesmo método o cal está definido da mesma forma:
<?php
class ContaBancaria {
    public float $saldo;

    public function devolverSaldo(){
        return $this->saldo;
    }
}
?>
  • Coa variable $this podemos 'acceder' aos valores do obxecto que está a facer uso do método. Cando $conta1 chama a dito método, $this e $conta1; cando $conta2 chama ao método, $this é $conta2 cos seus datos específicos.

Rexistrando clases

  • Para non ter que repetir un include ao principio de cada páxinas por cada unha das clases que necesitemos, podemos facer uso da autocarga de clases.
Do que se trata é de que cando fagamos uso dunha clase, a páxina PHP a inclúa automaticamente sen ter que facelo nos manualmente. Para iso podemos facer uso da...
  • Antigamente se recomendaba que estas clases tivera no nome un sufixo .class da forma NomeClases.class.php.
Na actualidade, se seguimos o [stándard indicado por PSR (PHP Standard Recommendations) https://www.php-fig.org/psr/] xa non é necesario.
Se seguimos o estándard de nomenclatura (PSR-4), as clases levan extensión .php sen empregar .class, da forma: NomeClase.php.
Exemplo:
<?php
    function cargadorClases($class) {
        require $class . '.php';
    }

    spl_autoload_register('cargadorClases');

?>
Liña 6: Indicamos o nome da función que vai 'cargar' as clases cando non se atopen definidas na páxina actual.
Liñas 2-4: Definimos a función indicada no método 'spl_autoload_register'. Dita función se define cunha parámetro, que vai ser o nome da clase a cargar cando non a atope.
No interior de dita función formamos o nome do arquivo a cargar en base ao nome da clase e o incluímos cunha das formas xa vistas anteriormente.
  • Podemos ter o código anterior dentro dun arquivo de include e incluílo por cada páxina que faga uso de clases.
Así:

Arquivo: incluir-clases.php:

<?php
    function cargadorClases($class) {
        require $class . '.php';
    }

    spl_autoload_register('cargadorClases');

Arquivo: DiscoDuros.php

<?php

class DiscosDuros {

    public string $numSerie;
    public string $marca;
    public string $capacidade=1;   // en TB

    public function getCapacidadeKB(): int {
        return $this->capacidade*1024*1024;
    }

}


Páxina exemplo.php.
Vai facer uso da clase DiscosDuros.
<?php
    include 'incluir-clases.php';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Exemplos de uso de clases</title>
    </head>
    <body>
        <?php
        
            $disco1 = new DiscosDuros();  // Estamos a utilizar a clase DiscosDuros creando un obxecto de dita clase.
            printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());
            echo "<br />";
            $disco2 = new DiscosDuros();
            printf("CAPACIDADE %s EN KB",$disco2->getCapacidadeKB());
        ?>
    </body>
    
</html>

Creando obxectos

  • Para crear un obxecto dunha clase usaremos a palabra new seguido do nome da clase. Isto devolverá un obxecto (instancia) da clase:
<?php
  $obxecto1 = new Clase();
  $obxecto2 = new Clase();
?>

Nota: Lembrar que para facer uso dunha clase teremos que tela incluída previamente.


  • Vexamos un exemplo:
<?php
    function cargadorClases($class) {
        require $class . '.php';
    }

    spl_autoload_register('cargadorClases');

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Exemplos de uso de clases</title>
    </head>
    <body>
        <?php
        
            $disco1 = new DiscosDuros();
            $disco2 = new DiscosDuros();
        ?>
    </body>
    
</html>

Nota: A partires de agora faremos un include do controlador que carga as clases cando se necesitan.

Accedendo as propiedades e métodos das clases

  • Unha vez que temos un obxecto dunha clase xa podemos acceder as súas propiedades e métodos.
Para iso temos que utilizar o operador -> desta forma:
 obxecto1->propiedade;
 obxecto1->nomeMétodo();
  • Vexamos un exemplo:
        <?php
            $disco1 = new DiscosDuros();
            $disco1->numSerie="1111A";
            $disco1->marca="Seagate";
            echo "<br />";
            printf("NUM.SERIE %s",$disco1->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco1->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());

            $disco2 = new DiscosDuros();
            $disco2->numSerie="2222B";
            $disco2->marca="Hitachi";
            echo "<br />";
            printf("NUM.SERIE %s",$disco2->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco2->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco2->getCapacidadeKB());
        ?>


  • Esta forma de acceder tamén pode empregarse dentro da clase para acceder aos seus propio métodos e atributos, pero utilizando a palabra reservada '$this'.
  • Vexamos un exemplo:
<?php

class DiscosDuros {
    public string $numSerie;
    public string $marca;
    public int $capacidade=1;   // en TB
    
    public function getCapacidadeKB(): int {
        return $this->capacidade*1024*1024;
    }
    public function getCapacidadeBytes(): int {
        return $this->getCapacidadeKB()*1024;
    }
    
    public function getMarca(): string {
        return $this->marca;
    }
}


  • A este tipo de propiedades/métodos soen denominarse 'de instancia'.
Cada obxecto ten un valor gardado diferente ao dos demais.



Fai os exercicios indicados neste punto. Solamente os da sección 'Definición de clases. Creación de obxectos e acceso a variables e métodos'.

Mantemento do estado

  • Para poder gardar un obxecto de forma persistente (que non se perda a información que ten e poidamos recuperala) é necesario 'transformalo' a unha cadea de texto que contén un fluxo de bytes, nun proceso que se chama serialización.
Isto é necesario xa que cando gardamos algo (nunha base de datos, ou nunha variable de sesión) é necesario que dita información pertenza a un tipo de datos, pero un obxecto está formado por propiedades con diferentes tipos de datos.
  • O procedemento é moi sinxelo:
  • Para convertilo empregamos a función serialice() da forma: $s = serialice($a); sendo $a un obxecto dunha clase.
Agora podemos gardar $s nunha base de datos por exemplo.
  • Para volvelo a convertir a un obxecto dunha clase, empregamos a función unserialice() da forma: $a = unserialice($s); sendo $s o obxecto previamente serializado.


  • No caso das variables de sesión, PHP xa serializa/deserializa un obxecto e non necesitamos empregar as funcións anteriores.
Por exemplo:
session_start();
$_SESSION['producto'] = $p;


......



$p = $_SESSION['producto'];



Herdanza

  • Na POO existen tres propiedades fundamentais: Herdanda, Polimorfismo e Encapsulación.
  • O concepto de herdanza é moi parecido ao que temos nos. Cando creamos unha clase que herda doutra, dita clase poderá acceder ás propiedades e métodos da clase pai.
A clase pai denomínase superclase e a clase filla subclase.
  • A sintaxe é a seguinte:
 class Pai {
   public string $var1;
   public string $var2;
  
   public function imprimirVar1(): void {
     echo string $var1;
   }
 }
 class Filla extends Pai {
   public string $var3;
   public function imprimirVar3(): void {
     echo $var3;
   }
 }
  • Liña 9: A clase Filla é subclase da clase Pai pola palabra clave extends.
  • Se agora creamos un obxecto da clase Filla, poderemos acceder aos atributos e métodos da clase pai. Así:
  $filla1 = new Filla();

  $filla1->var1='valor';
  $filla1->imprimirVar1();
  $filla1->var3=55;
  $filla1->imprimirVar3();
Nota: Cando vexamos os modificadores de visibilidade (public, protected, privated) veremos que unha subclase herda as propiedades e métodos declarados como public ou protected).
  • A herdanza permite reutilizar eficientemente o código da clase base.
  • Vexamos un exemplo cos discos creados anteriormente.
  • Nunha tenda adicada aos compoñentes informáticos podemos ter discos duros, pantallas, procesadores,...
Podemos crear unha clase Compoñente que teñas as propiedades comúns a todos eles (prezo, nome, num_serie,...)


  • Exemplo de herdanza:

Arquivo: Componentes.php

<?php

class Componentes {
    public string $numSerie;
    public string $nome;
    public float $prezo;
    public string $marca;


    public function getNumSerie(): string {
        return $this->numSerie;
    }
    public function getNome(): string {
        return $this->nome;
    }
    public function getPrezo(): float {
        return $this->prezo;
    }
    public function getMarca(): string {
        return $this->marca;
    }

}


Arquivo: DiscosDuros.php

<?php

class DiscosDuros extends Componentes{
    public int $capacidade=1;   // en TB

    public function getCapacidadeKB(): int {
        return $this->capacidade*1024*1024;
    }
    public function getCapacidadeBytes(): int {
        return $this->getCapacidadeKB()*1024;
    }

}

Arquivo: principal.php

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);  // Non debería ser necesario xa que amosa posibles erros de configuración no php.ini ou erros antes da execución do script, pero podemos poñelo por se acaso.
error_reporting(E_ALL);

include 'incluir-clases.php';
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">

    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Exemplos de uso de clases</title>
    </head>
    <body>
        <?php
            $disco1 = new DiscosDuros(); // Tamén ten o da clase Compoñente
            $disco1->numSerie="1111A";
            $disco1->marca="Seagate";
            $disco1->prezo=100.23;
            echo "<br />";
            printf("NUM.SERIE %s",$disco1->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco1->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());
            echo "<br />";
            printf("PREZO %s euros",number_format($disco1->getPrezo(),2));
 
            $disco2 = new DiscosDuros();
            $disco2->numSerie="2222B";
            $disco2->marca="Hitachi";
            $disco2->capacidade=5;
            $disco2->prezo=150.73;
            echo "<br />";
            printf("NUM.SERIE %s",$disco2->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco2->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco2->getCapacidadeKB());            
            echo "<br />";
            printf("PREZO %s euros", number_format($disco2->getPrezo(),2));
        ?>
    </body>
</html>


Resultado:
NUM.SERIE 1111A
MARCA 0.000000
CAPACIDADE 1048576 EN KB
PREZO 100.23 euros

NUM.SERIE 2222B
MARCA Hitachi
CAPACIDADE 5242880 EN KB
PREZO 150.73 euros


Nota: Se queres imprimir todos os datos dun obxecto podedes empregar a función var_dump(obxecto).


Facede os exercicios indicados neste punto. Soamente os da sección 'Herdanza'.

Construtores

  • O construtor é un método 'especial' que se chama de forma automática cando creamos un obxecto dunha clase, é dicir, cando empregamos a instrución new
Utilízase sobre todo para mandar valores iniciais a un obxecto creado.
  • A forma de definir un construtor é:
void __construct ([ mixed $args = "" [, $... ]] )
Nota: A diferenza de Java non podemos ter definidos varios construtores con diferentes parámetros.


  • Aplicamos este concepto ao exercicio anterior:

Arquivo: Componentes.php

    <?php

    class Componentes {
        public string $numSerie;
        public string $nome;
        public float $prezo;
        public string $marca;


        function __construct(string $numSerie, string $nome, float $prezo, string $marca) {
            $this->numSerie=$numSerie;
            $this->nome=$nome;
            $this->prezo=$prezo;
            $this->marca=$marca;
        }
     .................

Arquivo: Principal.php

        <?php
            $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete"); // Tamén ten o da clase Compoñente
            $disco1->capacidade=1;
            echo "<br />";
            printf("NUM.SERIE %s",$disco1->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco1->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());
            echo "<br />";
            printf("PREZO %s euros",number_format($disco1->getPrezo(),2));
 
            echo "<br />";
            echo "<br />";
            $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi");
            $disco2->capacidade=5;
            echo "<br />";
            printf("NUM.SERIE %s",$disco2->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco2->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco2->getCapacidadeKB());            
            echo "<br />";
            printf("PREZO %s euros", number_format($disco2->getPrezo(),2));
        ?>
    </body>
Fixarse como o construtor está definido na clase Componentes, xa que é aí onde están definidos os atributos da clase.
  • Como vemos, falta o atributo capacidade, pero ese atributo é específico da clase DiscoDuros. Polo tanto imos crear un construtor en dita clase, que vai ter como parámetros todos os anteriores máis o atributo 'capacidade'.
A pregunta é, se xa temos na clase superior (superclase) un construtor que asina os atributos aos valores enviados ao construtor, non hai forma de chamar a dito construtor dende a clase filla ?
A resposta é afirmativa: parent::__construct()
Apliquemos isto ao exemplo anterior:

Arquivo: DiscoDuros.php

<?php
class DiscosDuros extends Componentes{
    public int $capacidade=1;   // en TB
 
    function __construct(string $numSerie, string $nome, float $prezo, string $marca, int $capacidade) {
        parent::__construct($numSerie, $nome, $prezo, $marca);
        $this->capacidade=$capacidade;
    }
    public function getCapacidadeKB(): int {
        return $this->capacidade*1024*1024;
    }
    public function getCapacidadeBytes(): int {
        return $this->getCapacidadeKB()*1024;
    }
 
}
  • Liña 5: Definimos un construtor con todos os atributos que espera a clase DiscoDuros.
  • Liña 6: Chamamos ao construtor da clase pai utilizando a palabra clave 'parent::'
  • Liña 7: Asinamos á variable $capacidade o valor enviado como parámetro no construtor.

Arquivo: Principal.php

        <?php
            $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete",1); // Tamén ten o da clase Compoñente
            echo "<br />";
            printf("NUM.SERIE %s",$disco1->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco1->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());
            echo "<br />";
            printf("PREZO %s euros",number_format($disco1->getPrezo(),2));
 
            echo "<br />";
            echo "<br />";
            $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
            echo "<br />";
            printf("NUM.SERIE %s",$disco2->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco2->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco2->getCapacidadeKB());            
            echo "<br />";
            printf("PREZO %s euros", number_format($disco2->getPrezo(),2));
        ?>
Fixarse como agora no 'new' dos obxectos enviamos todos os valores, incluído a capacidade.


Como implementar varias construtores

  • En Java podemos ter varios construtores á vez definidos, de tal forma que un deles diferénciase doutro polo número ou tipo de argumentos.
Isto en PHP non o podemos facer.
Para solucionalo, temos que empregar un único constructor no que imos obter o número de parámetros que enviamos e en función diso, inicializaremos as propiedades correspondentes.
As funcións que temos que empregar dentro de __construct son:


  • Unha forma sinxela de facelo sería o seguinte:
class Proba
{
 $atrib1;
 $atrib2;

 function __construct() {
      $args = func_get_args();
      $num = func_num_args();
      switch ($num) {
            case 0: // Chamamos ao constructor sen parámetros
                $this->$atrib1 = 10;
                $this->$atrib2 = 10;
                break;
            case 1:  // Chamamos ao constructor con 1 parámetro
                $this->atrib1= func_get_arg(0); // Os argumentos empezan en 0
                $this->atrib2 = 10;  // Valor por defecto
                break;
            case 2: // Chamamos ao constructor con 2 parámetros
                $this->atrib1= func_get_arg(0);
                $this->atrib2= func_get_arg(1);
        }

    }
}




Outra forma máis complexa (código obtido deste enlace) a podemos implementar có seguinte código:

    function __construct()
       {
           $a = func_get_args();
           $i = func_num_args();
           if (method_exists($this,$f='__construct'.$i)) {
               call_user_func_array(array($this,$f),$a);
           }
       }
O que vai facer este código é chamar a un procedemento de nome __constructXX sendo XX o número de argumentos.
Así se eu crea un obxecto dunha clase no que quero enviar dous argumentos poñería:
 $obx1 = new Clase($val1,$val2);
Isto chamará a o construtor por defecto o cal chamará a outro método:
 function __construct2($par1,$par2){
 }
Fixarse como o nome do método acaba en 2 que se corresponde có número de argumentos.


  • Poderíamos aplicar isto ao exemplo dos DiscosDuros, de tal forma que podemos ter dous construtores, un cun os cinco parámetros e outro no que a capacidade colla un prezo por defecto.


Arquivo: DiscoDuros.php

<?php

class DiscosDuros extends Componentes{
    public int $capacidade=1;   // en TB

    
    function __construct() {
      $args = func_get_args();
      $num = func_num_args();
      switch ($num) {   //ORDEN CONSTRUCTOR SUPERIOR => $numSerie,$nome,$prezo,$marca 
            case 3: // Enviamos 3 datos: num_serie (arg(0)), nome (arg(1)) e marca (arg(2))
                parent::__construct(func_get_arg(0), func_get_arg(1), 500, func_get_arg(2));  // Enviamos un prezo por defecto en caso de non enviar o dato
                $this->capacidade = 100;    // Podemos dar un valor por defecto ao dato non enviado
                break;
            case 4:  // Enviamos 4 datos: num_serie (arg(0)), nome (arg(1)), marca (arg(2)) e capacidade (arg(3))
                parent::__construct(func_get_arg(0), func_get_arg(1), 0, func_get_arg(2));  // Neste caso enviamos 0 como prezo por defecto
                $this->capacidade = func_get_arg(3);
                break;
            case 5:  // Chamamos ao constructor con 5 parámetros: num_serie (arg(0)), nome (arg(1)), prezo (arg(2)), marca (arg(3)) e capacidade (arg(4))
                parent::__construct(func_get_arg(0), func_get_arg(1), func_get_arg(2),func_get_arg(3));
                $this->capacidade = func_get_arg(4);
                break;
        }
    }

    public function getCapacidadeKB(): int{
        return $this->capacidade*1024*1024;
    }
    public function getCapacidadeBytes(): int{
        return $this->getCapacidadeKB()*1024;
    }

}


  • Agora podemos chamar aos dos construtores:
   $disco1 = new DiscosDuros("1111A","Disco Duro","Seagete",2); 
   $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);


Constructores en clases fillas

  • Cando temos unha xerarquía de clases en forma de herdanza, cando unha clase filla define un constructor ten que chamar explícitamente ao constructor da clase pai coa forma: parent::__construct(parámetros).
Por exemplo:
Clase Pai:
class ArchivoBase {
    protected $handle;

    public function __construct($ruta) {
        echo "Abriendo archivo...\n";
        $this->handle = fopen($ruta, 'w');
    }

    public function escribir($texto) {
        fwrite($this->handle, $texto . "\n");
    }

}


Clase filla:
class Logger extends ArchivoBase {

    public function __construct($ruta) {
        echo "Logger iniciado\n";
        parent::__construct($ruta);
    }

    public function log($mensaje) {
        $this->escribir($mensaje);
    }
 
}



Facede os exercicios indicados neste punto. Soamente os da sección 'Constructores'.



Destructores

  • Ao igual que os construtores tamén dispoñemos dun método 'especial' denominado destrutor o cal se chama cando se deixa de ter referencias a un obxecto.
Cando remata o script todas as referencias pérdense e polo tanto se chamará ao método __destruct.
Non temos control sobre 'cando' se vai chamar a dito método.
Normalmente o empregaremos nos exemplos para levar constancia de 'cantos' obxectos creamos dunha clase por darlle unha funcionalidade nos nosos exemplos, pero sen ten un control de cando se chama non o empregaremos nunha situación real.
Normalmente se emprega para liberar recursos ou facer algún tipo de log para cando se destrúa un obxecto.


Vexamos un exemplo:

Arquivo: Componentes.php

    <?php

    class Componentes {
        static int $numComponentes = 0;
        
        public string $numSerie;
        public string $nome;
        public float $prezo;
        public string $marca;


        function __construct(string $numSerie, string $nome, float $prezo, string $marca) {
            $this->numSerie=$numSerie;
            $this->nome=$nome;
            $this->prezo=$prezo;
            $this->marca=$marca;
        }
    
        public function getNumSerie(): string{
            return $this->numSerie;
        }
        public function getNome(): string{
            return $this->nome;
        }
        public function getPrezo(): float{
            return $this->prezo;
        }
        public function getMarca(): string{
            return $this->marca;
        }
        function __destruct(){
            echo "<br />Acabouse";
        }

    }
        <?php
            $disco1 = new DiscosDuros("1111A","Disco Duro","Seagete",2); // Tamén ten o da clase Compoñente
            echo "<br />";
            printf("NUM.SERIE %s",$disco1->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco1->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco1->getCapacidadeKB());
            echo "<br />";
            printf("PREZO %s euros",number_format($disco1->getPrezo(),2));

            echo "<br />";
            $disco1=null;
            echo "<br />";
            echo "Segundo disco";
            echo "<br />";
            $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
            echo "<br />";
            printf("NUM.SERIE %s",$disco2->numSerie);
            echo "<br />";
            printf("MARCA %s",$disco2->marca);
            echo "<br />";
            printf("CAPACIDADE %s EN KB",$disco2->getCapacidadeKB());            
            echo "<br />";
            printf("PREZO %s euros", number_format($disco2->getPrezo(),2));
        ?>
Dará como resultado:
NUM.SERIE 1111A
MARCA Seagete
CAPACIDADE 2097152 EN KB
PREZO 100.00 euros
Acabouse
Segundo disco

NUM.SERIE 2222B
MARCA Hitachi
CAPACIDADE 6291456 EN KB
PREZO 150.73 euros Acabouse



Destructores en clases fillas

  • Ao igual que no caso dos constructores, se temos unha xerarquía de clases relacionadas pola herdanza, se sobreescribimos un __destruct dunha filla, esta debe chamar explicitamente ao __destruct da clase pai para que se execute.


Por exemplo:
Clase Pai:
class ArchivoBase {
    protected $handle;

    public function __construct($ruta) {
        echo "Abriendo archivo...\n";
        $this->handle = fopen($ruta, 'w');
    }

    public function escribir($texto) {
        fwrite($this->handle, $texto . "\n");
    }

    public function __destruct() {
        echo "Cerrando archivo...\n";
        fclose($this->handle);
    }

}


Clase filla:
class Logger extends ArchivoBase {

    public function __construct($ruta) {
        echo "Logger iniciado\n";
        parent::__construct($ruta);
    }

    public function log($mensaje) {
        $this->escribir($mensaje);
    }

    public function __destruct() {
        echo "Logger destruido\n";
        parent::__destruct(); 
    }
}

Polimorfismo e Sobrecarga

Polimorfismo

  • Outra das propiedades da POO é o Polimorfismo.
Normalmente o polimorfismo dáse en clases que manteñan unha relación de herdanza, aínda que tamén se pode dar en outro tipo de relacións (por exemplo utilizando interfaces).
Basicamente, é a capacidade que teñen as clase de definir métodos có mesmo nome e o mesmo número (e tipo en outras linguaxes) de argumentos.
Cando un obxecto chame a dito método ou use unha propiedade, saberá que método/propiedade utilizar en base a súa pertenza a un tipo de clase determinado.
  • Vexamos un exemplo aplicado ao caso dos DiscosDuros.
Imaxinemos que creamos un método de nome 'comprobarDatos' que o que fai é que no caso dos DiscosDuros, mira que a capacidade teña un valor positivo e no caso dos Compoñenetes, o prezo teña un valor positivo. Devolverá 1 ou 0 dependendo do valor.
Se eu creo un obxecto da clase DiscosDuros e chamo a dito método, chamará ao definido na clase DiscosDuros por pertencer a ela. Dende a clase DiscosDuros vou poder chamar ao método da clase superior utilizando a expresión parent::.

Arquivo: DiscosDuros.php

<?php

class DiscosDuros extends Componentes{

    .........
    public function comprobarDatos(): bool {
        if (parent::comprobarDatos()==0) return false;
        if ($this->capacidade < 0) {
            echo "<br />Capacidade negativa !!!<br />";
            return false;
        } else {
            return true;
        }
    }
}


Arquivo: Componentes.php

<?php
    class Componentes {
        ...................
        public function comprobarDatos(): bool {
            if ($this->prezo<0) {
                echo "<br />Prezo negativo!!!<br />";
                return false;
            }
            else {
                return true;
            }
        }

    }


Arquivo: principal.php

<?php
            $disco1 = new DiscosDuros();
            $disco1->prezo=-100;
            $disco1->capacidade=10;
            printf("O Prezo é negativo. Datos correctos?:%b",$disco1->comprobarDatos());
            $disco1->prezo=100;
            $disco1->capacidade=-10;
            printf("Capacidade negativa. Datos correctos?:%b",$disco1->comprobarDatos());
?>

Saída:

Prezo negativo!!!
O Prezo é negativo. Datos correctos?:0
Capacidade negativa !!!
Capacidade negativa. Datos correctos?:0

Sobrecarga

  • Dicimos que un método está sobrecargado se está definido dúas ou máis veces nunha clase e se diferenza un doutro polo número (e tipo en outras linguaxes) de argumentos.
En PHP non podemos ter sobrecarga de métodos xa que non deixa ter definidos varios métodos có mesmo nome.
Un 'apaño' que podemos facer é o seguinte (parecido ao que fixemos cos construtores):
<?php
class Proba {
    function __call($method_name, $arguments) {
           $i = count($arguments);
           if (method_exists($this,$f=$method_name.$i)) {
               call_user_func_array(array($this,$f),$arguments);
           }
    }
    private function metodo1($a){
        echo "<br />Chamada a 'metodo' cun argumento";
    }
    private function  metodo2($a,$b){
        echo "<br />Chamada a 'metodo' con dous argumentos";;
    }
}
<?php

  $p1 = new Proba();

  $p1->metodo(1);
  $p1->metodo(1,'Proba');
?>


Dará como resultado:
Chamada a 'metodo' cun argumento
Chamada a 'metodo' con dous argumentos


Esta é unha función especial que se chama cando un obxecto chama a unha función que non estea definida. Recibe como datos o nome da función e os parámetros enviados na súa chamada.


Nota: Fixarse que as funcións están declaradas como 'private' para que dende a páxina que faga uso da clase non aparezan os métodos (en forma de axuda) no IDE de PHP cando tecleamos o nome do obxecto. Veremos a continuación a encapsulación.

Atributos e Métodos de clase

  • Un método/atributo de clase pode ser chamado/usado sen necesidade de instanciar un obxecto.
Chámase directamente dende o nome da clase.
O concepto de clase o podemos asociar ao de variables globais nun programa tradicional.
Se as variables dos obxectos son variables (atributos) 'locais' a cada un, é dicir, cada obxecto ten un valor propia para cada atributo da clase, nas variables de clase (estáticas) todos os obxectos teñen o mesmo valor, xa que fisicamente están apuntando á mesma dirección de memoria.
Se un obxecto cambia o valor dun atributo de clase, se cambia para todos os obxectos.
  • Para declarar unha variable ou método de clase, debemos antepoñer a palabra reservada static.
Para acceder a unha variable dende fora da clase debemos de poñer: Clase::$variableClase, sendo Clase o nome da clase.
Vexamos un exemplo:
class Clase {
  static $variableStatic = 10;
}
  
  echo Clase::$variableStatic;


  • Ao igual que os atributos, podemos crear métodos de clase.
Para acceder dende un método (de clase ou static) a un atributo static temos que facer uso da palabra clave: self:: cando estamos dentro da clase
Vexamos un exemplo:
class Clase {
  static int $variableStatic = 10;

  static function metodoStatic(): void {
     echo self::$variableStatic;
  }
  function metodo(): void {
     echo self::$variableStatic;
  }

}
  Clase::metodoStatic(); // Chama ao método de clase
  $ob1 = new Clase();
  $obj1->metodo();  // Chama ao método e este accede á variable de clase.
Fixarse como para chamar a un método de clase usamos a forma: Clase::métodoClase()


  • Vexamos agora un exemplo de aplicación no exemplo dos DiscosDuros.
Podemos crear unha variable de clase que garde o número de discos duros/compoñentes creados.
Cada vez que eu creo un compoñente aumentarei o número e se o destrúo (non teño ningunha referencia) diminúo o contador. Farei o mesmo para a clase DiscosDuros e ademais crearei un método de clase que me amose o número total (de todos os compoñentes) e o número de discos duros.
  • Solución:
Arquivo: Componentes.php
    <?php

    class Componentes {
        static int $numComponentes = 0;
        
        public string $numSerie;
        public string $nome;
        public float $prezo;
        public string $marca;


        function __construct(string $numSerie,string $nome,float $prezo,string $marca) {
            $this->numSerie=$numSerie;
            $this->nome=$nome;
            $this->prezo=$prezo;
            $this->marca=$marca;
            
            self::$numComponentes+=1;
        }
        static function imprimirTotal(): void{
        
            printf("Número de compoñentes:%d<br />",self::$numComponentes);
        }

    
        public function getNumSerie(): string{
            return $this->numSerie;
        }
        public function getNome(): string{
            return $this->nome;
        }
        public function getPrezo(): float{
            return $this->prezo;
        }
        public function getMarca(): string{
            return $this->marca;
        }
        function __destruct(){
            self::$numComponentes-=1;
        }

    }
Arquivo: DiscosDuros.php
<?php

class DiscosDuros extends Componentes{
    public int $capacidade=1;   // en TB
    public static int $numDiscosDuros=0;


    
    function __construct() {
      self::$numDiscosDuros+=1;
      $args = func_get_args();
      $num = func_num_args();
      switch ($num) {   //ORDEN CONSTRUCTOR SUPERIOR => $numSerie,$nome,$prezo,$marca 
            case 3: // Enviamos 3 datos: num_serie (arg(0)), nome (arg(1)) e marca (arg(2))
                parent::__construct(func_get_arg(0), func_get_arg(1), 500, func_get_arg(2));  // Enviamos un prezo por defecto en caso de non enviar o dato
                $this->capacidade = 100;    // Podemos dar un valor por defecto ao dato non enviado
                break;
            case 4:  // Enviamos 4 datos: num_serie (arg(0)), nome (arg(1)), marca (arg(2)) e capacidade (arg(3))
                parent::__construct(func_get_arg(0), func_get_arg(1), 0, func_get_arg(2));  // Neste caso enviamos 0 como prezo por defecto
                $this->capacidade = func_get_arg(3);
                break;
            case 5:  // Chamamos ao constructor cun parámetro
                parent::__construct(func_get_arg(0), func_get_arg(1), func_get_arg(2),func_get_arg(3));
                $this->capacidade = func_get_arg(4);
                break;
        }
    }

    static function imprimirTotal(): void{
        Componentes::imprimirTotal();
        printf("Número de compoñentes:%s<br />",self::$numComponentes);
        printf("Número de discos:%s<br />",self::$numDiscosDuros);
        
    }

    public function comprobarDatos(): bool{
        if (!parent::comprobarDatos()) return false;
        if ($this->capacidade < 0) {
            echo "<br />Capacidade negativa !!!<br />";
            return false;
        } else {
            return true;
        }
    }

    public function getCapacidadeKB(): float{
        return $this->capacidade*1024*1024;
    }
    public function getCapacidadeBytes(): float{
        return $this->getCapacidadeKB()*1024;
    }

    function __destruct(){
        parent::__destruct();
        self::$numDiscosDuros-=1;
    }
    
}
Arquivo: principal.php:
        <?php
        
        
            echo "<br />";
            echo "Primeiro disco";
            echo "<br />";
            $disco10 = new DiscosDuros("1111A","Disco Duro","Seagete",2); // Tamén ten o da clase Compoñente
            echo DiscosDuros::imprimirTotal();
            
            $disco10=null;
            echo "<br />";
            echo "Primeiro disco borrado";
            echo "<br />";
            echo DiscosDuros::imprimirTotal();
            $disco12 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
            $disco13 = new DiscosDuros("3333B","Disco Duro",150.73,"Hitachi",6);
            $disco14 = new DiscosDuros("4444B","Disco Duro",150.73,"Hitachi",6);
            echo "<br />";
            echo "Tres novos discos";
            echo "<br />";
            echo DiscosDuros::imprimirTotal();
        ?>

Facede os exercicios indicados neste punto. Soamente os da sección 'Atributos e métodos de clase'.

Constantes

  • Un pouco relacionado co punto anterior, temos as constantes.
Son valores fixos establecidos na definición da clase, que non se poden modificar en tempo de execución.
  • Para declarar unha constante no interior dunha clase usamos a palabra reservada const antes do nome da constante que non debe levar o caracter $.
Como norma, o nome de constante debe estar en en maiúsculas para diferenciar facilmente unha constante dunha variable.
class Clase {

   const NUM_MAXIMO=1000;  // A partires de php 7.1 se pode poñer public ou private
}
  • Por defecto a constante é pública se non poñemos modificador ningún (como calquera variable). Podemos establecer os modificadores de protected e private.


  • Para acceder á constante podemos facelo como se fora un atributo estático (polo tanto, na memoria está a ocupar unha posición que é compartida por todos os obxectos, como sucede nas variables de clase). Podemos acceder directamente utilizando o nome da clase ou a través dun obxecto da forma:
 $a = new Clase();

 echo $a::NUM_MAXIMO;
 echo Clase::NUM_MAXIMO;

Constantes predefinidas en PHP

  • Tedes neste enlace algunhas constantes que vos poden servir na programación PHP.
  • De todas elas, vos pode axudar na programación en PHP (sobre todo en aloxamentos compartidos de Internet):
  • __FILE__: Ruta completa e nome do arquivo. Usado dentro dun INCLUDE devolverá o nome do ficheiro do INCLUDE.
  • __DIR__: Directorio do ficheiro. Usado dentro dun INCLUDE, devolverá o directorio do arquivo incluído.
Por que ?
Se estades nun aloxamento compartido cun CMS (como o Wordpress que utilizamos na práctica e queredes facer un include dun arquivo php, dando a ruta absoluta do voso aloxamento, teredes que averiguar dita ruta. Unha das formas é facendo un echo dunha das constantes anteriores dende un Post ou páxina do CMS.

Encapsulación

  • Outra das propiedades da POO é a Encapsulación.
Mediante dita propiedade 'obrigamos' a que o uso dos datos e métodos se fagan de acordo ao implementado polo programador.
Ocúltanse (a o que vai facer uso da clase) aqueles métodos e propiedades que non vai ter que utilizar e evítase que os datos poidan ter valores non válidos.
En definitiva, a encapsulación é un mecanismo no que organizamos os datos e métodos de tal forma que evitamos o acceso a os datos de calquera outra forma diferente á especificada. A encapsulación garante a integridade dos datos que contén un obxecto.
  • A encapsulación impleméntase cunha destas tres palabras clave:
  • Público(public): é o modificador por defecto, co cal se non poñemos nada enténdese que o modificador é public. Calquera pode acceder ás propiedades e métodos declarados como public.
  • Privado(private): o acceso as propiedades e métodos declarados como private están restrinxidos a clase na que foron creados.
  • Protexido(protected): unicamente poden acceder a estas propiedades e métodos a propia clase e as súas clases derivadas, é dicir, clases que sexan 'fillas' da clase onde o atributo/método estea declarado como protected.
Estes modificadores van poder ser aplicados tanto a propiedades como a métodos.
Vexamos un exemplo aplicado ao caso dos DiscosDuros...
Supoñamos que cando creo un DiscoDuro e doulle un prezo, quero que en función da capacidade aplique un desconto ou outro. Isto o fai un método que non quero que sexa 'visible' fora do código da clase.
Polo tanto terei que declaralo como 'private'. Como o desconto o vou poder aplicar a todos os compoñentes, o vou definir na clase Componentes, e o vou facer 'protected' para que o poida referenciar a subclase 'DiscosDuros' pero que non poida acceder directamente dende fora da clase Componentes.

Arquivo: Componentes.java

<?php

class Componentes {
    static int $numComponentes = 0;

    public string $numSerie;
    public string $nome;
    public float $prezo;
    public string $marca;

    protected float $desconto=0;

    function __construct(string $numSerie, string $nome, float $prezo, string $marca) {
        $this->numSerie=$numSerie;
        $this->nome=$nome;
        $this->prezo=$prezo;
        $this->marca=$marca;

        self::$numComponentes+=1;
    }

    public function getDesconto(): float{
        return $this->desconto;
    }

    ......................


Arquivo: DiscosDuros.php

<?php

class DiscosDuros extends Componentes{
    public int $capacidade=1;   // en TB

    function __construct(string $numSerie, string $nome, float $prezo, string $marca, int $capacidade) {
        parent::__construct($numSerie, $nome, $prezo, $marca);
        $this->capacidade=$capacidade;
        
        if($capacidade>5){
            $this->desconto=10; // Faremos un desconto dun 10%
        } else {
            $this->desconto=3;  // Faremos un desconto dun 3%
        }
    }
    ................


Arquivo: principal.php

        <?php
  
           $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete",1); // Tamén ten o da clase Compoñente
            echo "<br />";
            printf("DISCO 1 DESCONTO %.2f%%",$disco1->getDesconto());
 
            echo "<br />";
            echo "<br />";
            $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
            printf("DISCO 2 DESCONTO %.2f%%",$disco2->getDesconto());
        ?>


Dará como resultado:
DISCO 1 DESCONTO 3%

DISCO 2 DESCONTO 10%


  • Fixarse como a única forma de acceder a unha variable 'private' dende o exterior de dita clase, é a través dun método (no exemplo 'getDesconto')


Protexendo os atributos

  • Normalmente, na POO imos querer que as propiedades dunha clase non poidan ser accedidas directamente, xa que imos querer ter un 'control' sobre os valores asinados.
A forma de realizar este control é que a asignación de valores se faga a través dun método, no que comprobamos o valor a asignar. Isto xa o podemos facer no construtor, pero se queremos modificar os valores durante a execución do programa, teremos que facer que os atributos sexan privados e crear os métodos para asinar os valores.


  • Nota: Noutras linguaxes coñecense como métodos get (obter o valor dun atributo) e métodos set(darlle un valor a un atributo).


Inicialmente poderíamos facer algo parecido a isto (aplicado ao exemplo dos DiscosDuros e Componentes)

Arquivo: DiscosDuros.php

<?php

class DiscosDuros extends Componentes{
    private int $capacidade=1;   // en TB

    function __construct(string $numSerie, string $nome, float $prezo, string $marca, int $capacidade) {
        parent::__construct($numSerie, $nome, $prezo, $marca);
        $this->capacidade=$capacidade;
        
        if($capacidade>5){
            $this->desconto=10; // Faremos un desconto dun 10%
        } else {
            $this->desconto=3;  // Faremos un desconto dun 3%
        }
        
    }
    public function setCapacidade(int $novoValor): bool {. // Se non necesito informar podo poñer void e non facer o return
        if ($novoValor<0) { // Non deixamos unha capacidade negativa
            return false;
        }
        else {
            $this->capacidade=$novoValor;
            return true;
        }
    }
    public function getCapacidade(): int{
        return $this->capacidade;
    }
  • Liña 4: Declaramos a capacidade como privada.
  • Liñas 17-25: Definimos un método cambiarCapacidade que vai comprobar se a capacidade é negativa. Se o é, retorna 0. En caso contrario, cambia a capacidade e retorno 1
  • Liñas 26-28: Definimos un método para que devolva a capacidade.


Arquivo: principal.php

        <?php
  
           $disco1 = new DiscosDuros("1111A","Disco Duro",100.23,"Seagete",1); // Tamén ten o da clase Compoñente
            echo "<br />";
            if ($disco1->setCapacidade(4)){
                echo "Capacidade cambiada <br />";
                printf("Nova capacidade Disco 1:%d",$disco1->getCapacidade());
            }
            else {
                echo "A capacidade do DISCO 1 non pode ser negativa";
            }
            
            echo "<br />";
            echo "<br />";
            $disco2 = new DiscosDuros("2222B","Disco Duro",150.73,"Hitachi",6);
            if ($disco1->setCapacidade(-2)){
                echo "Capacidade cambiada <br />";
                printf("Nova capacidade Disco 2:%d",$disco1->getCapacidade());
            }
            else {
                echo "A capacidade do DISCO 2 non pode ser negativa";
            }
Da como resultado:
Capacidade cambiada
Nova capacidade Disco 1:4

A capacidade do DISCO 2 non pode ser negativa


Eu penso que vai depender da aplicación e de como ides necesitar modificar os valores das propiedades dunha clase.
Se por exemplo, non ides modificar os valores e soamente ides darlles uns valores iniciais (irían no construtor, onde podedes validalos) non necesitaríamos crear un método 'set' para darlle un valor a unha propiedade e como no código non teríamos asignacións, poderíamos non ter un método 'get'.
Se a nosa clase vai ser utilizada en outros proxectos e o uso indebido das propiedades pode dar lugar a problemas, deberíamos ter un método 'set' por cada propiedades para controlar que os valores son os correctos.



Métodos máxicos

  • PHP incorpora dous métodos 'especiais' chamados máxicos que son chamados automaticamente (parecido ao que fixemos coa función __call) cando accedemos a unha propiedade dunha clase calquera:
  • Método __get: Se chama automaticamente cando intentamos acceder a unha propiedade calquera dunha clase. Leva como parámetro o nome do atributo do que queremos obter o valor.
Por exemplo:
class Clase{

 private $propiedade;

 public function __get($atributo) {  
      return $this->$atributo;  // Hai que poñer $atributo para que o substitúa polo seu valor, se non estariamos a intentar devolver un atributo de nome $atributo...
 }  
}
  $obj = new Clase();
  echo $obj->propiedade;


  • Método __set: Set chámase automaticamente cando intentamos dar un valor a unha propiedade dunha clase. Ten como parámetros de entrada o nome do atributo e o valor que se lle quere dar.
Por exemplo:
class Clase{

 private $propiedade1;
 private $propiedade2;

 public function __set($atributo,$valor) {  
      $this->$atributo=$valor;
   }  
 } 
}
  $obj = new Clase();
  $obj->propiedade1=10;
  $obj->propiedade2=10;


  • Relacionado cos dous métodos anteriores temos a función property_exists. A necesitamos utilizar para comprobar se o atributo que estamos intentar modificar ou obter o seu valor existe.
Teremos que facer uso da constante __CLASS__, que devolve o nome da clase 'actual'.
No caso de __get:
class Clase{

 private $propiedade;

 public function __get($atributo) {  
      if (property_exists(__CLASS__, $atributo)) { 
        return $this->$atributo;
      }  
      return NULL;
 } 
}
  $obj = new Clase();
  echo $obj->propiedade;


No caso de __set:
class Clase{

 private $propiedade1;
 private $propiedade2;

 public function __set($atributo,$valor) {  
      if (property_exists(__CLASS__, $atributo)) { 
         $this->$atributo=$valor;
      }
      else {
          echo "Non existe o atributo $atributo";
      }
   }  
 } 
}
  $obj = new Clase();
  $obj->propiedade1=10;
  $obj->propiedade2=10;
  • O tratamento que queirades darlle cando o atributo non exista vai depender do programador. Poderíamos retornar un 0/1 como fixamos antes cos métodos que asignaban un valor a unha propiedade private.
No exemplo aparecería un echo.


Facer os exercicios indicados neste punto.

Funcións relacionadas coas clases e métodos

  • PHP dispón de funcións que nos van permitir saber o nome da clase a que pertence un obxecto, preguntar por se unha clase está definida, saber se un método existe nunha clase,...
Php POO Encapsulac 1.jpg
Imaxe obtida do enlace anterior


  • Outra función relacionada coas clases e que poderemos necesitar dela é a función instanceof.
A súa función é comprobar se unha variable é dunha clase determinada.
Un código de exemplo sería o seguinte:
 $p = new Clase();

 if ($p instanceof Clase){
   echo "O obxecto \$p é da clase Clase";
 }


Operacións con obxectos

Referencias

  • Unha referencia en PHP vai permitir que varias variables 'apunten' fisicamente á mesma dirección de memoria, permitindo que se unha delas modifica o valor o resto das variables que fan referencia tamén verán modificado o seu valor.
Para facer unha referencia a outra variable simplemente teremos que igualalas (a partires da versión PHP5):
 $ob1 = new Clase();
 $ob1->propiedade = 5;

 $ob2 = $ob1;
 $ob2->propiedade = 10;  // Agora $ob1-> propiedade vai ter de valor 10

Nota: Lembrar que no caso doutro tipo de datos crearíase unha copia nova (non sería unha referencia).


Clonar obxectos

  • Clonar un obxecto é facer unha copia exacta do mesmo, pero fisicamente estarán ocupando posicións de memoria diferentes, polo que non teremos unha referencia como no caso anterior.
 $ob1 = new Clase();
 $ob1->propiedade = 5;

 $ob2 = clone($ob1);
 $ob2->propiedade = 10;  // $ob1-> propiedade mantén o seu valor a 5


Comparar obxectos

  • Temos dous operadores para comparar dous obxectos:
  • O operador de comparación simple (==): dará como resultado verdadeiro se os obxectos que se comparan son instancias da mesma clase e os seus atributos teñen os mesmos valores.
  • O operador de identidade (===): dará como resultado verdadeiro se as variables comparadas son referencias á mesma instancia.
 $ob1 = new Clase();
 $ob1->propiedade = 5;

 $ob2 = $ob1;
 $ob3 = clone($ob1);

 // $ob1==$ob2 => Dará como resultado true xa que teñen os mesmos valores.
 // $ob1===$ob2 => Dará como resultado true xa que unha é unha referencia á outra

 // $ob1==$ob3 => Dará como resultado true xa que teñen os mesmos valores.
 // $ob1===$ob3 => Dará como resultado false xa que unha non é referencia da outra

Métodos máxicos

Algún deles xa os vimos anteriormente, na encapsulación.
  • Comentar o método __toString: Este método devolverá un string cando se usa o obxecto coma se fose unha cadea de texto, por exemplo dentro dun echo ou dun print. Debe devolver unha cadea de texto.
  class Clase {
    $propiedade='valor';

    public function __toString(){
       return 'Isto aparece nun echo:' . $this->propiedade;
    }
  }


 $ob1 = new Clase();

 echo $ob1;
O resultado será:
Isto aparece nun echo:valor


  • Este método o usaremos cando vexamos o acceso a base de datos.
Dunha consulta a unha base de datos obteremos un array de obxectos dunha clase. Normalmente teremos que visualizar o contido dese array.
 echo "<ol>";
 foreach ($arrayObxecto as $obxecto) {
   printf("<li>%s</li>",$obxecto);
 }
 echo "</ol>";
O resultado será unha lista sen ordenar no que se visualizará o indicado no método __toString da clase á que pertence $obxecto.


Facer os exercicios indicados neste punto.

Clases abstractas

  • A partires de PHP5 introducíronse na linguaxe as clases e os métodos abstractos.
Para que unha clase sexa abstracta debe levar a palabra clave abstract.
abstract class Clase {

}
  • As clases abstractas teñen estas características:
  • Non se poden crear obxectos a partir delas, isto é: unha clase abtracta non pode ser instanciada.
  • Unha clase abstracta pode incorporar métodos abstractos, que son aqueles dos que so existe a súa declaración, deixando a implementación para as clases fillas ou derivadas.
  • Unha clase abstracta pode incorporar métodos non abstractos.
  • Para que se utilizan ?
Normalmente ides necesitar crealas cando queirades ter unha clase que sexa 'base' doutras e 'obrigar' a implementar certos métodos.
Por exemplo, imaxinade que estades a facer unha aplicación no que queredes modelizar as figuras xeométricas.
Así, tedes a figura Cadrado, Circulo, coas súas propiedades.
Eu como deseñador quere que todas esas clases implementen o procedemento debuxar (que é diferentes para cada unha delas).
Faría isto:
abstract class FiguraXeometrica {

   abstract public function debuxar();
 
}
Agora, calquera clase que derive de FiguraXeometrica terá que implementar a método debuxar obrigatoriamente.


  • Nota:Unha clase abstracta pode ter propiedades e métodos con código que serán herdadas polas subclases.



Facer os exercicios indicados neste punto.

Interfaces

  • As interfaces son un tipo especial de clases que se caracterizan en que soamente levan as definicións de métodos, pero sen ningunha implementación.
Cando outra clase queira facer uso da interface terá que obrigatoriamente implementar o código dos métodos que están definidos na interface.
As interfaces, ao igual que as clases abstractas non poden ser instanciadas.
As interfaces, ao igual que as clases abstractcas poden empregar a herdanza con outras interfaces


  • O concepto é parecido ao das clases abstractas, pero ten dúas diferenzas importantes:
  • Para utilizar unha interface non teño que herdar de dita clase, se non que simplemente incorpora a interface (con todos os seus métodos) á miña clase.
Unha clase vai poder utilizar unha ou varias interfaces. Se empregásemos as clases abstractas soamente podemos herdar dunha.
  • Unha interface non pode ter código nos métodos que deben ser públicos e soamente permite definir constantes, non se poden empregar atributos. É obrigatorio poñer código aos métodos nas clases que implementen a interface.


Como se declara ? Utilizando a palabra clave interface:
interface ClaseInterface {
  public function metodo1(): int;   // É un exemplo de tipo de dato devolto. Se queremos que poida devolver calquera tipo, non poñer nada
  public function metodo2(): string;
}
Como vemos os métodos non levan código.


Para utilizar dita interface, deberemos utilizar a palabra clave implements:
class Clase implements ClaseInterface {

  public function metodo1(): int {
    ....
  }
  public function metodo2(): string {
    ....
  }

}
Podemos combinar varias interfaces da forma:
class Clase implements ClaseInterface1,ClaseInterface2 {

  public function metodo1(): int {
    ....
  }
  public function metodo2(): string {
    ....
  }
  public function metodo3(): string {
    ....
  }

}


As interfaces tamén se poden utilizar con clases fillas:
class Clase extends ClasePai implements ClaseInterface1,ClaseInterface2 {

  public function metodo1(): int {
    ....
  }
  public function metodo2(): string {
    ....
  }
  public function metodo3(): string {
    ....
  }

}


  • As interfaces van permitir definir métodos cun nome específico e cun número de parámetros determinado.
Así, se por exemplo, teño unha tenda no que teñamos diferentes tipos de produtos formando listas. Cada lista estará formada por un tipo de produto determinado, e eu quero que aquelas que o necesiten, poidan buscar un produto da súa lista. A implementación da busca será diferente por cada tipo de produto. Podo crear unha interface, de tal forma que para buscar sempre vou mandar un único parámetro como dato a utilizar na busca. Calquera clase que necesite buscar terá que incorporar a miña interface e terá que implementar o código específico, pero obrigatoriamente terá que levar o nome do procedemento indicando por min e o parámetro indicado por min na interface:
interface Busca {

  public function buscaProduto(int $valor): string ;

}

Namespaces


  • Os espazos de nomes proporcionan unha maneira de agrupar clases, interfaces, funcións e constantes relacionadas.
Tamén vai servir para solucionar o problema de que utilicemos clases ou código de terceiros (desenvolvido por outras persoas) no que pode darse o caso de que se chamen igual varias clases, constantes, funcións,..., polo que teríamos un erro ao intentar utilizalas.
  • Tamén van poder utilizarse para abreviar nomes extra-largos que poidamos ter nos nomes de clases, mellorando a lexibilidade do código fonte.


  • Calquera código PHP pode estar dentro dun namespace (espazo de nome) pero soamente vense afectado o seguinte tipo de código: clases (incluíndo abstractas e traits), interfaces, funcións e constantes.

Declaración

  • Os espazos de nomes decláranse utilizando a palabra reservada namespace.
Un ficheiro que conteña un espazo de nomes debe declaralo ao comezo do mesmo, antes que calquera outro código ou espazo en branco, cunha excepción: a palabra reservada declare.


<?php
namespace MiProyecto;

const CONSTANTE_1 = 1;
class Clase { /* ... */ }
function funcion_1() { /* ... */ }

Nota: Nos exemplos estamos a utilizar clases, pero lembrar, como está indicado ao principio, que poderíamos ter funcións, constantes...


  • Pódese definir o mesmo espazo de nomes en varios ficheiros, permitindo a separación do contido dun espazo de nomes a través do sistema de ficheiros.
Por exemplo:

Arquivo físico: Arquivo1.php

<?php
namespace MiProyecto;

const CONSTANTE_1 = 1;
class Clase1 { /* ... */ }
function funcion_1() { /* ... */ }

Arquivo físico: Arquivo2.php

<?php
namespace MiProyecto;

const CONSTANTE_2 = 1;
class Clase2 { /* ... */ }
function funcion_2() { /* ... */ }


  • Un espazo de nome o podemos identificar cun cartafol nun sistema de arquivos. En diferentes cartafoles podemos ter o mesmo nome de arquivo. Para referenciar a un arquivo teremos que antepoñer o nome do cartafol (ruta relativa/absoluta) ao nome do arquivo.
  • Aínda que non é obrigatorio, crearemos un cartafol por cada un dos namespaces.
Por exemplo, se teño unha clase MiClase dentro do namespace 'experimento', creamores un cartafol de nome experimento e dentro del poñeremos a clase miclase.php.

Uso

  • Para referenciar a unha clase que se atopa definida nun espazo de nome de nome 'Espazo' teremos que poñer:
obj = new Espazo\Clase();
Sendo Clase unha clase definida no espazo de nomes 'Espazo' da forma:
<?php
namespace Espazo;
class Clase {
  ...............
}


Imaxinemos que no caso da clase Componentes, o noso sitio tamén xestiona compoñentes dos coches. Tamén teremos definida unha clase Componentes no que gardaremos:

Arquivo: Coches/Componentes.php

<?php
namespace ClasesCoches;

class Componentes {
    
    public float $prezo;
    public string $modelo;
    public int $ano_comercializacion;
    
}
Fixarse que, como estamos a dar un nome ao arquivo físico igual ao nome da clase, non van poder estar fisicamente no mesmo cartafol, por iso creamos un cartafol de nome /Coches/ onde estarán todas as clases que teñan que ver cos compoñentes dos coches.

Arquivo: Informatica/Componentes.php

<?php
namespace ClasesInformatica;
class Componentes {
  public string $numSerie;
  public string $nome;
  public float $prezo;
  public string $marca;
}
O mesmo facemos coas clases que teñan que ver con compoñentes informáticos, e creamos un cartafol de nome /Informatica/ onde gardaremos as clases dos compoñentes informáticos.


  • Como vemos, creamos un espazo de nome 'ClasesInformatica' e outro 'ClasesCoches'.
  • Para poder utilizar ditas clases, teremos que referencialas polo seu espazo de nome, xa que a clase Componentes podería facer referencia tanto a clase gardada no espazo de nomes ClasesInformatica ou a clase gardada no espazo de nome ClasesCoches:


Arquivo: Principal.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<?php

  require ('Coches/Componentes.php');
  require ('Informatica/Componentes.php');
  
?>
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
    <head>
        <meta charset="utf-8" />
        <title>Exemplos de códigos php</title>
    </head>
    <body>

    <?php   
        $objCoche1 = new ClasesCoches\Componentes();
        $objInfor1 = new ClasesInformatica\Componentes();
    ?>
    </body>    
</html>
  • Liñas 5-6: Incluímos os arquivos físicos onde están definidas as clases.
  • Liñas 17-18: Creamos un obxecto de cada clase. Fixarse como están referenciadas as clases de cada espazo de nome.



  • Nota: Normalmente o que se fai cando se van empregar clases que están noutro espazo de nome é empregar use despois do require, da forma: use name_space\nome_clase;

Sub-espazos

  • Ao concepto aprendido no punto anterior podemos sumarlle o concepto de sub-espazo, que é cando temos unha clase que está definida non espazo de nomes dentro doutro espazo de nomes. Sería como un cartafol dentro dun cartafol no sistema de arquivos.
<?php
namespace MiñasClases\OutrasClases;
class Clase {

}
<?php
  $obj1 = new Miñasclases\OutrasClases\Clase();


No exemplo dos compoñentes, poderíamos ter un espazo para as clases que teñan relación cos Computadores, outro espazo para os Móbiles,... Fixarse que fisicamente poden estar no mesmo cartafol (/Informatica/) mentres non teñan nomes iguais.
  • Aínda que non é obrigatorio, crearemos un cartafol por cada un dos namespaces e subespazos.
Por exemplo, se teño unha clase MiClase dentro do namespace 'experimento', creamores un cartafol de nome experimento e dentro del poñeremos a clase miclase.php.



Alias

  • Se creamos unha estrutura de espazos de nomes moi grande, pode darse o caso de que para referenciar a unha clase teñamos que poñer algo parecido a isto:
<?php
  $obj1 = new Miñasclases\OutrasClases\Outras\MaisClases\Clase();
Para evitalos podemos facer uso dos alias. Un alias é un nome que fai referencia a un conxunto de espazos de nomes.
Así,
<?php
namespace Espazo\SubEspazo1\SubEspazo2\SubEspazo3;
class Clase {

}
Agora, para referenciar a clase creo un alias do seu espazo de nome:
<?php
   require ('Clase.php');

   use Espazo\SubEspazo1\SubEspazo2\SubEspazo3 as EspazoSub;

   $ob1 = new EspazoSub\Clase(); 
?>
  • Liña 4: Creamos un alias de nome 'EspazoSub' que é equivalente a poñer Espazo\SubEspazo1\SubEspazo2\SubEspazo3.
  • Liña 5: Facemos referencia á clase Clase por medio do alias.


Nota: Se non poñemos o 'as EspazoSub' collerá como alias a última parte do use. No exemplo sería SubEspazo3.



Referenciando outros namespaces

Imaxinemos que temos a Clase1 dentro do espazo Espazo1 e a clase Clase2 dentro do espazo Espazo2,

  • Se temos varios espazos diferentes y queremos referenciar a clases definidas noutros espazos teríamos que:
  • Ter un require/include da clase que imos a empregar. Lembrar que isto é o lugar físico onde se atopa o arquivo PHP.
  • Facer o use da forma: use Espazo\Clase;

No exemplo anterior, se Clase1 emprega a Clase2 tería:

<?php

   namespace Espazo1;

   require ('Clase2.php');
   use Espazo2\Clase2;

   class Clase1 {
        ...........
        $clase2 = new Clase2();
   }

?>



IMPORTANTE: Cando dentro dun namespaces facemos unha referencia a unha clase e queremos acceder a unha clase global da linguaxe (por exemplo, as clases mysqli para traballar contra bases de datos) non as va a atopar, xa que ao definir un namespace vai buscar as clases que se atopan dentro do mesmo.

No exemplo anterior:

<?php

   namespace Espazo1;

   require ('Clase2.php');
   use Espazo2\Clase2;

   class Clase1 {
        ...........
        $clase2 = new Clase2();
        $conexion = new mysqli("host", "usuario", "contraseña", "base_de_datos");   // NON A VAI ATOPAR
   }

?>


Para solucionalo temos dúas opcións:
  • Empregar o operador de resolución de ámbito global: Isto é, poñer \ antes do clase a empregar. Por exemplo: $conexion = new \mysqli("host", "usuario", "contraseña", "base_de_datos");
  • Declarar use ao principio do arquivo:
::<?php

   namespace Espazo1;
   use mysqli;

   require ('Clase2.php');
   use Espazo2\Clase2;

   class Clase1 {
        ...........
        $clase2 = new Clase2();
        $conexion = new mysqli("host", "usuario", "contraseña", "base_de_datos");   // AGORA SI A VAI ATOPAR
   }

?>




Facer os exercicios indicados neste punto



Documentación

  • Para documentar código PHP existe un estándard parecido a Java (javadoc) coñecido como PHPDOC.
Proporciona unha forma coherente de documentar clases, métodos, propiedades, constantes e máis en PHP.


  • Características Principais de PHPDoc:
  • Comentarios de Documentación: Utiliza comentarios de varias liñas comezando con /** e terminando con */ para documentar elementos do código.
  • Etiquetas: PHPDoc utiliza etiquetas especiais que comezan con @, como @param, @return, @throws, @var, etc., para proporcionar información específica.
  • Descricións: Permite engadir descricións lexibles para clases, métodos, parámetros e valores de retorno.
  • Compatibilidade con Ferramentas: Moitas ferramentas e IDEs como PhpStorm, Visual Studio Code e outros, recoñecen e utilizan os comentarios de PHPDoc para proporcionar intellisense, comprobación de tipos e outras funcionalidades.


  • Exemplo de Uso de PHPDoc:
<?php

/**
 * Clase para representar un Libro.
 *
 * @package MiProyecto\Modelo
 */
class Libro {

    /**
     * Título do libro.
     *
     * @var string
     */
    protected string $titulo;

    /**
     * Asigna o título do libro.
     *
     * @param string $titulo Título do libro.
     * @return void
     */
    public function setTitulo(string $titulo): void {
        $this->titulo = $titulo;
    }

    /**
     * Obten o título do libro.
     *
     * @return string Título do libro.
     */
    public function getTitulo(): string {
        return $this->titulo;
    }
}
  • Neste exemplo, cada elemento importante da clase Libro está documentado usando comentarios de PHPDoc.
  • Beneficios de Usar PHPDoc:
  • Mellora a Lexibilidade: Fai que o código sexa máis fácil de entender para outros desenvolvedores.
  • Soporte para Xeración de Documentación Automática: Ferramentas como phpDocumentor poden xerar documentación do código automaticamente baseándose nestes comentarios.
  • Axuda no Desenvolvemento: IDEs modernos utilizan PHPDoc para proporcionar autocompletado, verificación de tipos e axuda contextual.


  • PHPDoc é esencial para manter un código PHP grande e complexo ben documentado, lexible e fácil de manter.




-- Ángel D. Fernández González -- (2025).