PHP Exercicios POO
Sumario
Definición de clases. Creación de obxectos e acceso a variables e métodos
- Un programador novato (PN) decide introducirse no mundo da POO e intenta implantar
unha solución informática para a xestión dos vehículos da Empresa de Transporte na que traballa. Decide utilizar como linguaxe de programación PHP.
- O problema que se lle expón é o seguinte: necesita almacenar información sobre os
distintos vehículos de que dispón a Empresa. Entre esta información está o ano de compra do vehículo, a súa matrícula, a súa marca.
- O PN decide implantar nunha clase, a información necesaria.
- Na páxina que vai amosar os datos (chamarémoslle Principal, o PN vai crear os catro vehículos de que dispón a Empresa neste momento, e vailles a asignar uns valores:
Exercicio: implantar a solución
Solución:
- Arquivo: Vehiculos.class.php
1 <?php 2 3 class Vehiculos{ 4 public $matricula; 5 public $marca; 6 public $ano; 7 8 }
- Arquivo: IncluirClases.inc.php
1 <?php 2 function cargadorClases($class) { 3 require $class . '.class.php'; 4 } 5 6 spl_autoload_register('cargadorClases');
- Arquivo: Principal.php
1 <?php 2 include 'IncluirClases.inc.php'; 3 ?> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 5 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 6 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> 7 <head> 8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 9 <title>Exemplos de uso de clases</title> 10 </head> 11 <body> 12 <?php 13 $veh1 = new Vehiculos(); 14 $veh2 = new Vehiculos(); 15 $veh3 = new Vehiculos(); 16 $veh4 = new Vehiculos(); 17 18 $veh1->marca = "Peugot"; 19 $veh1->matricula = "C-1234-BZ"; 20 $veh1->ano = 1999; 21 22 $veh2->marca = "Fiat"; 23 $veh2->matricula = "C-4325-AZ"; 24 $veh2->ano = 1998; 25 26 $veh3->marca = "Opel"; 27 $veh3->matricula = "C-2342-AF"; 28 $veh3->ano = 1996; 29 30 $veh4->marca = "Ford"; 31 $veh4->matricula = "C-4322-CF"; 32 $veh4->ano = 2000; 33 ?> 34 </body> 35 36 </html>
- Comproba que non lle deu erros, pero queda coa dúbida se terá almacenados os valores dunha forma correcta, polo que é necesario que imprima devanditos valores.
- Para 'imprimir' os valores, necesita un procedemento (método) que os saque por pantalla.
- Así que decide crear dentro da clase Vehículo, un método que imprima devandita información. Podería facer un único método que imprima o ano, matrícula e marca á vez, pero decide crear tres métodos, un para cada tipo de información a imprimir, de nome impAno, impMatricula, impMarca, por se necesita mostrar a información de forma individualizada.
- Unha vez implantados, decide probalos, a ver se mostran a información correcta, Para iso modifica a páxina Principal, facendo que cada obxecto Vehículo chame a cada un dos métodos.
Solución:
- Arquivo: Vehiculos.class.php
1 <?php 2 3 class Vehiculos { 4 public $matricula; 5 public $marca; 6 public $ano; 7 8 public function impMatricula() { 9 printf("<div>%s</div>",$this->matricula); 10 } 11 public function impMarca() { 12 printf("<div>%s</div>",$this->marca); 13 } 14 public function impAno() { 15 printf("<div>%s</div>",$this->ano); 16 } 17 18 }
- Arquivo: Principal.php
1 ........... 2 3 echo "<b>Datos veh1</b><br />"; 4 $veh1->impMatricula(); 5 $veh1->impMarca(); 6 $veh1->impAno(); 7 8 echo "<b>Datos veh2</b><br />"; 9 $veh2->impMatricula(); 10 $veh2->impMarca(); 11 $veh2->impAno(); 12 13 echo "<b>Datos veh3</b><br />"; 14 $veh3->impMatricula(); 15 $veh3->impMarca(); 16 $veh3->impAno(); 17 ...........
Nota: Soamente se amosa o código engadido á páxina Principal.
Herdanza
- O PN atópase bastante satisfeito do conseguido ata agora, pero isto só era unha pequena parte do que ten que facer. Digamos que a súa empresa adícase ao transporte de
diñeiro, concretamente dous dos seus vehículos que son furgonetas, e que cada vehículo pode transportar unha cantidade de diñeiro. Ademais cada furgoneta leva consigo un número de vixiantes xurados. Devandita información é necesario almacenala.
- Ante esta situación, o PN decide crear unha nova clase, Furgoneta, cos procedementos
da clase Vehículo e os novos atributos (cantidade de diñeiro e número de vixiantes xurados). Pero cando ía empezar a implantar devandita solución, aparece o Programador Experto, alguén que xa traballou en Xava moitos anos, e ao ver o que ía facer, explícalle que en Xava, ao ser unha Linguaxe de POO pódese realizar o que se chama Herdanza. É dicir, crear unha subclase que herde todo o que ten a superclase.
- Con esta gran vantaxe, o PN decide crear un subclase Furgoneta da superclase Vehículo. Dentro da nova clase Furgoneta, implementa os novos atributos (cantidade de diñeiro e número de vixiantes
xurados), xa que son atributos propios da clase Furgoneta, que non ten a clase Vehículo. Por outra banda, como o PN quererá mostrar a información destes dous novos atributos, tamén crea, dentro da propia clase Furgoneta, dous métodos, para mostrar devanditos atributos de nome impDiñeiro, impXurados.
- Para probar esta nova clase, vai ter que modificar a súa páxina Principal, xa que tiña implantados catro obxectos da clase Vehiculos, pero agora sabe que dúas deses vehículos son Furgonetas, polo que terá que cambiar o seu código, e se antes tiña catro
vehículos da forma:
1 $veh1 = new Vehiculos(); 2 $veh2 = new Vehiculos(); 3 $veh3 = new Vehiculos(); 4 $veh4 = new Vehiculos();
- Agora terá dous vehículos e dúas Furgonetas da forma:
1 $veh1 = new Vehiculos(); 2 $veh2 = new Vehiculos(); 3 $furg1 = new Furgonetas(); 4 $furg2 = new Furgonetas();
- A cada un dos seus vehículos (furgonetas e vehículos) asignaralles os valores aos seus
atributos e chamará aos métodos que imprimen devanditos valores.
- O PN realiza todo o anterior, comprobando que todo é correcto.
Solución:
Arquivo: Furgonetas.class.php
1 <?php 2 3 class Furgonetas extends Vehiculos { 4 public $diñeiro; 5 public $numVixiantes; 6 7 public function impDiñeiro() { 8 printf("<div>%s</div>",$this->diñeiro); 9 } 10 public function impNumVixiantes() { 11 printf("<div>%s</div>",$this->numVixiantes); 12 } 13 14 }
Arquivo: Principal.php
1 <body> 2 <?php 3 $veh1 = new Vehiculos(); 4 $veh2 = new Vehiculos(); 5 $furg1 = new Furgonetas(); 6 $furg2 = new Furgonetas(); 7 8 $veh1->marca = "Peugot"; 9 $veh1->matricula = "C-1234-BZ"; 10 $veh1->ano = 1999; 11 12 $veh2->marca = "Fiat"; 13 $veh2->matricula = "C-4325-AZ"; 14 $veh2->ano = 1998; 15 16 $furg1->marca = "Opel"; 17 $furg1->matricula = "C-2342-AF"; 18 $furg1->ano = 1996; 19 20 21 $furg2->marca = "Ford"; 22 $furg2->matricula = "C-4322-CF"; 23 $furg2->ano = 2000; 24 25 $furg1->diñeiro = 1000; 26 $furg1->numVixiantes = 1; 27 $furg2->diñeiro = 5000; 28 $furg2->numVixiantes = 3; 29 30 echo "<b>Datos veh1</b><br />"; 31 $veh1->impMatricula(); 32 $veh1->impMarca(); 33 $veh1->impAno(); 34 35 echo "<b>Datos veh2</b><br />"; 36 $veh2->impMatricula(); 37 $veh2->impMarca(); 38 $veh2->impAno(); 39 40 echo "<b>Datos Furgoneta 1</b><br />"; 41 $furg1->impMatricula(); 42 $furg1->impMarca(); 43 $furg1->impAno(); 44 $furg1->impDiñeiro(); 45 $furg1->impNumVixiantes(); 46 47 echo "<b>Datos Furgoneta 2</b><br />"; 48 $furg2->impMatricula(); 49 $furg2->impMarca(); 50 $furg2->impAno(); 51 $furg2->impDiñeiro(); 52 $furg2->impNumVixiantes(); 53 ?> 54 </body>
- O PN pensa agora que as súas outros dous vehículos (que son coches), non transportan diñeiro, senón documentos segredos. Cada coche transporta un documento segredo, do cal é necesario gardar o seu nome, así como o nome do condutor que leva devandito coche.
- O PN pensando da mesma forma que o caso das furgonetas, agora sabe que pode crear unha subclase (chamada Coches, por exemplo) da superclase Vehiculos. En dita subclase estarán os atributos NomeCond e NomeDoc. Polo tanto implementa dita subclase e os dous atributos así como os métodos necesarios para mostralos (impNomeDoc, impNomeCond)
- Unha vez feito isto, o PN modifica a páxina Principal, igual que fixo no caso das Furgonetas para probar todo o novo.
Solución:
Construtores
- Recapitulemos o que fixemos ata este momento. creei 3 clases (Vehiculos, Coches e Furgonetas), as cales poden almacenar información que eu necesito, así como os métodos necesarios para imprimir (mostrar) dita información.
- Por outra banda, creei outra páxina Principal, a cal vai facer uso das clases anteriores, mediante a creación de 4 vehículos, dous de tipo Coches e dous de tipo Furgonetas.
- Cada un destes vehículos é unha instancia da clase correspondente e van ter almacenados uns valores concretos. Se eu quixese ter almacenado mais información sobre outros coches, non tería mais que crear un novo obxecto (instanciar) da clase correspondente.
- O PN séguese rompendo o ‘coco’ para implantar de forma informática todo o proceso da súa empresa. O seguinte que pensa é en refinar un pouco máis o feito ata agora.
- Primeiro pensa que sería conveniente ter un método que lle dese valores ás variables ou atributos de que dispomos en cada clase. É dicir, que no canto de pór:
$furg1->marca = "Opel"; $furg1->matricula = "C-2342-AF"; $furg1->ano = 1996; $furg1->diñeiro = 1000; $furg1->numVixiantes = 1;
chamásese a un método con 5 parámetros, de tal forma que cada un destes parámetros, será asignado a cada atributo, da forma seguinte:
$furg1->asignarValores($param1, $param2, $param3, $param4, $param5)
onde:
$this->marca = $param1 $this->matricula = $param2 $this->ano = $param3 $this->nomeDoc = $param4 $this->nomeCond = $param5
- Así poderiamos pór nunha única liña o que antes tiñamos en cinco: $furg1->asignarValores("Peugot","C-1234-BZ",1999, "Documento segredo1","Angel");
- Ante esta brillante idea, o PN disponse a implantala. Primeiro pensa onde situar o método que asigna os valores dos parámetros aos atributos e inmediatamente dáse conta de que non pode situalo na clase Vehiculos, xa que en devandita clase non existen os atributos nomeDoc e nomeCond, polo que decide situalos nas subclases. Así, na subclase Coches e na subclase Furgonetas, decide crear un método de nome 'asignarValores' de cinco parámetros, nos que se asigna os valores ás cinco variables ou atributos de que dispomos.
Nota: Podedes probalo ou seguir lendo :)
- Pero velaquí que volve o Programador Experto a coller un bolígrafo que se esqueceu e observa o que o PN disponse a facer.
- - !!!!! Pero que feixes !!!!!
- Como se ve que levas pouco tempo nisto de Xava e da POO. Para realizar a asignación inicial de variables pódese utilizar un método especial, chamado construtor, o cal chámase cada vez que se realiza un new, é dicir, cada vez que se crea un obxecto dunha clase. O nome do construtor chámase __construct, podendo levar ou non parámetros.
- Ante a cara de asombro e incomprensión do PN (a parte de porse vermello como unha brasa), o Programador Experto dille:
- - Vouche a pór un exemplo para que o entendas:
- Supoñamos que dispoño dunha clase denominada Proba, con dous atributos da forma:
class Proba { $atrib1; $atrib2; }
e dunha páxina Principal, a cal fai uso da clase Proba, da forma:
1 <?php 2 $miProba = new Proba(); 3 ?>
- Supoñamos que quero que os dous atributos que vai ter o obxecto (atrib1, atrib2) teñan un valor por defecto, por exemplo 10. Para facer isto, creo o que se chama un construtor, que non é máis que
un método como outro calquera, pero ao cal PHP chama cada vez que se fai un new.
- Así. modifico a clase Proba e creo o construtor da forma:
1 class Proba 2 { 3 $atrib1; 4 $atrib2; 5 6 function __construct() { 7 $atrib1 = 10; 8 $atrib2 = 10; 9 } 10 }
- Agora na páxina Principal,
1 <?php 2 $mProba = new Proba(); // Chama ao construtor 3 ?>
- Neste momento, $mProba->atrib1 ten o valor 10, igual que $mProba->atrib2.
- O PN ante esta demostración de sabedoría non sabe dicir outra cousa que:
- - Ahhhhhhhhhhhhhhhhhhh
- - Pero isto non é todo, dille o Programador Experto.
- Resulta que se poden ter definidos tantos construtores como se queira, sempre que se diferencien no número ou tipo de argumentos (xa que o nome é fixo). Así, eu podería ter outro construtor para asignar valores concretos aos dous atributos da forma (xa vimos que en php isto non pode ser directamente, explicado na teoría):
1 class Proba 2 { 3 $atrib1; 4 $atrib2; 5 6 function __construct() { 7 $a = func_get_args(); 8 $i = func_num_args(); 9 if ($i==0){ 10 $atrib1 = 10; 11 $atrib2 = 10; 12 } 13 elseif (method_exists($this,$f='__construct'.$i)) { 14 call_user_func_array(array($this,$f),$a); 15 } 16 17 } 18 private function __construct2($valor1, $valor2) { 19 $this->atrib1=$valor1; 20 $this->atrib2=$valor2; 21 } 22 23 }
- De tal forma que agora podo crear un obxecto da clase Proba e asignarlles valores aos seus atributos da forma:
1 <?php 2 $mProba = new Proba(10,20); // Chama ao construtor con dous parámetros 3 ?>
- A isto denomínaselle sobrecargar un método (overload). É dicir, ter dentro dunha clase varios métodos co mesmo nome, pero con distinto tipo ou número de argumentos, dille o Programador Experto cun certo aire de superioridade....(en PHP isto non é exactamente así xa que os métodos en realidade teñen diferentes nomes :) )
- O PN ponse risoño como un paxaro ao comprender o que o Programador Experto explícalle (aínda que un pouco mosqueado).
- Agora sabe que no caso da clase Coches e a clase Furgonetas, debe crear un construtor que teña cinco parámetros, asignando a cada atributo o valor do parámetro. A cada parámetro asígnalle un nome: param1, param2,....e posteriormente dentro do construtor, asigna os valores deses parámetros a cada variable. Así na clase Coches terá 5 parámetros que asignará a marca, ano, matricula, nomeCond e nomeDoc e no caso de Furgonetas asignará a marca, ano, matricula, diñeiro e numXurados.
Solución:
- Ben, di o PN, isto marcha. A verdade é que desta forma aforreime moito código en asignacións, pero aínda así hai algo que non me cadra...
- Se observo o código, resulta que asignamos os atributos da clase Vehiculos na clase Coches e Furgonetas, e que este código está repetido. Se aplico o mesmo concepto de construtor, podería ter un construtor na clase Vehiculos, que asigne valores iniciais os tres atributos que pertencen a esta clase, quedando os construtores das clases Coches e Furgonetas coa asignación aos seus atributos correspondentes. Isto é moi bonito, pero pódese facer ? como podo chamar ao construtor da clase Vehiculos desde o construtor da clase Coches e a clase Furgonetas ?
- O PN inicia unha procura exhaustiva coa documentación que posúe e despois de moitas cuncas de café cunhas poucas gotas de whisky, descobre que en PHP pódese utilizar dúas palabras craves:
- $this: é unha referencia á instancia actual (ao obxecto actual). É dicir, supoñamos que temos un obxecto da clase Coches (miCoche). Este obxecto é unha instancia da clase Coches. Se eu asigno á variable $miCoche->marca = "Citroen" e posteriormente chamo a un método da forma $miCoche->metodo() no que teño a instrución $this->marca, estou a referirme aos valores da instancia (obxecto) que chamou a este método (neste caso miCoche). $this é o equivalente a 'miCoche', é dicir, poderíase chamar a calquera método ou referenciar a calquera variable do obxecto miCoche.
- super::: fai referencia aos métodos e variables da superclase. Só se utiliza en caso de ter dúas clases relacionadas mediante unha herdanza, na que dentro da subclase queiramos referenciar algún atributo e método da superclase.
- O PN ponse moi contento e decide tomarse unha cervecita por descubrir esta información tan útil. Fará o seguinte:
- Primeiro, modificará os nome dos paramétros nos dous construtores creados, xa que cos que tiña, a primeira ollada non se enteraba para que servían (o nome non era moi significativo). Daralles os mesmos nomes que os atributos da clase.
- Segundo, creará un construtor na clase Vehiculos, con tantos parámetros como atributos teña a clase, para chamalo desde a clase Coches e Furgonetas. Como o vai a facer ? Mediante o uso da palabra super. Desde o construtor de cada unha das clases anteriores, chamará ao construtor da clase superior (Vehiculos)
Solución:
Atributos e métodos de clase
-- Ángel D. Fernández González -- (2016).