Foros del Web » Programando para Internet » PHP »

Clases POO. Teoría.

Estas en el tema de Clases POO. Teoría. en el foro de PHP en Foros del Web. Hola compañeros; Estoy comenzando con POO. En internet hay manuales y un sinfín de artículos repetitivos con el funcionamiento básico, pero a la hora de ...
  #1 (permalink)  
Antiguo 30/03/2018, 14:52
 
Fecha de Ingreso: julio-2008
Mensajes: 241
Antigüedad: 9 años, 9 meses
Puntos: 9
Clases POO. Teoría.

Hola compañeros;

Estoy comenzando con POO. En internet hay manuales y un sinfín de artículos repetitivos con el funcionamiento básico, pero a la hora de decir aquí estamos y esto quiero conseguir es cuando se nos abre el millón de preguntas. Necesito algún ejemplo avanzado del que aprender (que vaya más allá de la sintaxis propia de definir clases).

El ejemplo típico es el de un sistema de bibliotecas. O por ejemplo de usuarios. O de lo que sea por tal de entender cómo trabajáis vosotros.

Imaginemos que tenemos esta clase:

Código:
class heladeria_services {
	public $id_service;
	public $flavor;
	public $model;
	public $date;

		public function __construct (	$var_id_service,
						$flavor,
						$model,
						$date )
		{
						$this-> id_servicio = $id_servicio;
						$this-> flavour = $flavor;
						$this-> model = $model;
						$this-> date = $date;
		}
Me lo he inventado sobre la marcha imaginando una heladería por ejemplo. Ahora bien... ¿Las funciones "guardar","mostrar" y "editar" cómo quedarían? ¿Cómo hago para que queden bien y poder jugar con los datos de un form (por ejemplo)?. La pregunta es cómo recoger los datos de un form y almacenarlo en la clase. O cómo recoger los datos de la clase y volcarlos a un php a parte.

Entiendo que así se definen las funciones:
Código:
public function getFlavor (){
			return  $this->flavor . "</br>";
		}
Pero mi pregunta recurrente es cómo recoger datos de un sitio, meterlos en la clase. Sacarlos de la clase y mostrarlos en otro sitio. Lo que quiero entender e cómo jugar con los datos de un lado para otro. No sé si me explico correctamente. Seguramente deba emplear los argumentos en las funciones para pasar datos y los return para devolver la información pero ¿cómo se devuelven varias variables? Y perdonad mi ignorancia pero quiero aprender bien y estudiar la forma en que vosotros trabajáis.

Quizás alguien tenga algún ejemplo que sea extenso y que maneje mis dudas. O algún referencia dónde aprender con ejemplos resueltos. O algún sistema más o menos extenso del que aprender. Un saludo!!
__________________
"La diversidad de opiniones crean una perspectiva capaz de ver todas las caras del objeto"

Última edición por winjose; 30/03/2018 a las 15:11
  #2 (permalink)  
Antiguo 02/04/2018, 17:39
Avatar de hhs
hhs
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.887
Antigüedad: 4 años, 9 meses
Puntos: 349
Respuesta: Clases POO. Teoría.

Hola, puedes ampliar un poco mas tu duda sobre lo que quieres hacer ? igual puedes usar el ejemplo que ya comenzaste para dar un poco mas de detalles.
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #3 (permalink)  
Antiguo 02/04/2018, 22:02
Avatar de alvaro_trewhela  
Fecha de Ingreso: octubre-2012
Ubicación: localhost
Mensajes: 885
Antigüedad: 5 años, 6 meses
Puntos: 103
Respuesta: Clases POO. Teoría.

Pero que sabes de poo?
Encapsulacion?
Herencia?
Polimorfismo?
Abstraccion?

A diferencia de programacion procidual, con poo debes manejar conceptos
  #4 (permalink)  
Antiguo 03/04/2018, 18:46
Avatar de mortiprogramador
Colaborador
 
Fecha de Ingreso: septiembre-2009
Ubicación: mortuoria
Mensajes: 3.793
Antigüedad: 8 años, 7 meses
Puntos: 212
Respuesta: Clases POO. Teoría.

Saludo

Pues teniendo en cuenta lo que mencionas, hagamos un ejemplo.

1. Digamos que tenemos esta clase en un archivo llamado Person.php

Código PHP:
Ver original
  1. class Person
  2. {
  3.     public $name;
  4.     protected $gender;
  5.     private $age;
  6.    
  7.     public function __construct($name, $gender, $age)
  8.     {
  9.         $this->name = $name;
  10.         $this->gender = $gender;
  11.         $this->age = $age;
  12.     }        
  13. }

Esta clase como se puede ver tiene 3 atributos
($name que es público, $gender que es protegido, y $age que es privado)

A su vez tiene un método inicial (el constructor) que se encarga
de recibir parámetros y asignarlos a estas variables.

2. Ya que tenemos esta clase, podemos crear un formulario html que nos pida
los datos de una persona (para el ejemplo los mismos tres)
(el formulario al mismo nivel de Person.php, es decir, la misma carpeta)

Código PHP:
Ver original
  1. <html>
  2.     <body>
  3.         <form method='post'>
  4.             Nombre:<input type='text' id='name' name='name' value='<?php echo @$_POST['name'];?>'>
  5.             <br>Género:<input type='text' id='gender' name='gender' value='<?php echo @$_POST['gender'];?>'>
  6.             <br>Edad:<input type='text' id='age' name='age' value='<?php echo @$_POST['age'];?>'>
  7.             <br><input type='submit'>
  8.         </form>
  9.     </body>
  10. </html>
  11. <?php
  12.     if( isset($_POST) && sizeof($_POST) )
  13.     {
  14.         include 'Person.php';
  15.         $person = new Person($_POST['name'],$_POST['gender'],$_POST['age']);
  16.         echo 'El nombre recibido es '.$person->name;
  17.         echo '<br>El género recibido es '.$person->gender;
  18.         echo '<br>La edad recibida es '.$person->age;
  19.     }
  20.      
  21. ?>


Cómo podemos ver, el formulario pide tres campos, y hará el envío.
Cuando se reciba, incluiremos el archivo Person.php del punto 1 (que es la clase creada antes)
para posteriormente usarlo para instanciar la clase Person.

Al hacer la instancia con new Person, se ejecutará por defecto el método constructor,
y es por esto que enviaremos los datos que nos llegaron vía POST del formulario.
Con esto, los atributos de la clase obtienen los valores capturados.

Aquí ya cubrimos lo que preguntabas respecto a cómo recoger los datos del form y almacenarlo
en la clase.

Ahora bien, como quiero ver la información que tiene ahora la clase, estoy invocando
a los atributos ($person->name, $person->gender y $person->age) PERO solo uno de ellos es público

Esto generará un error por temas de visibilidad de los atributos (en el caso de protected y private)
pues no podemos acceder directamente a ellos.

Para esto, se hace necesario agregar dos funciones a nuestra clase

Código PHP:
Ver original
  1. public function getGender()
  2. {
  3.     return $this->gender;
  4. }
  5.  
  6. public function getAge()
  7. {
  8.     return $this->age;
  9. }

Estas dos funciones son públicas, y retornarán los valores de las variables
sin necesidad de tener que modificar el ámbito de las mismas (es decir, por ej, dejarlas public)

Y por ende, ahora haremos este llamado:

Código PHP:
Ver original
  1. echo 'El nombre recibido es '.$person->name;
  2. echo '<br>El género recibido es '.$person->getGender();
  3. echo '<br>La edad recibida es '.$person->getAge();


Con esto, estamos invocando a las nuevas funciones quienes nos devolverán los datos que necesitamos.

Finalmente, agreguemos una función más a la clase que se encarge de guardar la información en una base de datos.

Código PHP:
Ver original
  1. public function save()
  2. {
  3.     $conn = mysqli_connect(self::$server, self::$user, self::$pass, self::$dbname);
  4.    
  5.     $query = 'INSERT INTO person (name, gender, age) VALUES (?,?,?)';
  6.     $stmt = mysqli_prepare($conn, $query);
  7.     mysqli_stmt_bind_param($stmt, 'ssd', $this->name, $this->gender, $this->age);
  8.     mysqli_stmt_execute($stmt);
  9.    
  10.     $affected_rows = mysqli_stmt_affected_rows($stmt);                
  11.    
  12.     $stmt->close();
  13.     $conn->close();
  14.    
  15.     return $affected_rows;
  16. }


Aquí vemos de entrada algo nuevo, el operador self::, ¿qué es esto?

Bueno, resulta que aparte de las propiedades que ya vimos (private, protected, public)
podemos agregar algo más a estas, convertirlas en estáticas (ideal para datos que NO cambiarán)

Un ejemplo de datos que no cambian (bueno, al menos no deberían cambiar tan seguido..)
son los de conexión a la base de datos.

Para esto, en la clase agregaré 4 datos más que serán privados Y estáticos.

Código PHP:
Ver original
  1. private static $server = 'localhost';
  2. private static $user = 'miusuario';
  3. private static $pass = 'micontraseña';
  4. private static $dbname = 'mibasededatos';


Y estos cuatro son los que se llaman con self::, que es el modo en que php
nos permite acceder a variables que son estáticas dentro de la misma clase que las define.

El resto de la función se encarga de luego de establecer la conexión,
crear el query de inserción de los datos, usar las variables que ya tienen los valores a guardar,
y realizar la operación retornando el resultado de la misma.

Y claro, para verificar visualmente, en nuestro archivo del formulario
agregaremos esto:

Código PHP:
Ver original
  1. if( $person->save() )
  2.     echo '<br>Registro guardado';
  3. else
  4.     echo '<br>Inconvenientes al guardar';


Un simple condicional que preguntará el resultado del llamado a la función save,
y en el caso que retorne 1 informará del registro guardado, en otro caso informará de inconvenientes al guardar.

Y con esto ya cubrimos también la manera de comunicar la clase con una base de datos.

Cómo nota final, este ejemplo necesita mejoras.
Por ejemplo, los datos de la base de datos no deberían estar en la clase Person,
puesto que esta solo debería tener los atributos de las personas.

Para solucionar eso, se podría crear una clase donde se maneje todo lo necesario
respecto a la base de datos como tal, y luego se modificaría el formulario para
que trabaje con las dos clases (es decir, la clase Person que ya existe, y la nueva de la base de datos)

También necesita validaciones, por ejemplo, la longitud de los datos a guardar,
si son numéricos o alfanuméricos, etc.

Y bueno, de ahí en adelante todo lo que de la imaginación.
Con esto creo que te distraes un rato, y si quieres distraerte más,
te recomiendo revises esto
e incluso te pasees por los frameworks que existen para trabajar en conjunto con php
(CodeIgniter, CakePhp, Symfony, Laravel, etc) que manejan ya todos estos conceptos
de comunicación entre los formularios (Vistas), la base de datos (Modelo) y la lógica de programación (Controlador).
__________________
"Si consigues ser algo más que un hombre, si te entregas a un ideal, si nadie puede detenerte, te conviertes en algo muy diferente."
Visita piggypon.com

Última edición por mortiprogramador; 03/04/2018 a las 18:52
  #5 (permalink)  
Antiguo 06/04/2018, 18:41
Avatar de hhs
hhs
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.887
Antigüedad: 4 años, 9 meses
Puntos: 349
Respuesta: Clases POO. Teoría.

Cita:
Estoy comenzando con POO. En internet hay manuales y un sinfín de artículos repetitivos con el funcionamiento básico, pero a la hora de decir aquí estamos y esto quiero conseguir es cuando se nos abre el millón de preguntas. Necesito algún ejemplo avanzado del que aprender (que vaya más allá de la sintaxis propia de definir clases).
Creo que con la explicación de mortiprogramador cubres la parte que corresponde a como hacer las cosas con el lenguaje. Me gustaria como complemento tratar un punto importante que es el diseño orientado a objetos y que se basa en los conceptos básicos ademas de otros principios que se han derivado de la solución y aplicación de los principios básicos que ya debes de saber.

Vamos a usar un ejemplo sencillo; Imagina que tienes que crear una aplicación de recursos humanos para una empresa y uno de los requerimientos es que cuando se contrate a un nuevo Empleado se pueda guardar el nombre junto con un puesto asignado y un salario, ademas debe de ser posible promoverlo a un nuevo puesto con su respectivo cambio de salario.

Muy posiblemente con lo que sabes ahora crees tu clase Empleado :
Código PHP:
Ver original
  1. class Employee
  2. {
  3.     private $name;
  4.     private $position;
  5.     private $salary;
  6.    
  7.     private static $server = 'localhost';
  8.     private static $user = 'miusuario';
  9.     private static $pass = 'micontraseña';
  10.     private static $dbname = 'mibasededatos';
  11.  
  12.  
  13.     public function __get($attribute) {
  14.         if(property_exists($this, $attribute)) {
  15.             return $this->{$attribute};
  16.         }
  17.        
  18.         throw new Exception('No existe esta propiedad');
  19.     }
  20.    
  21.     public function __set($attribute, $value) {
  22.         if(property_exists($this, $attribute)) {
  23.             $this->{$attribute} = $value;
  24.         }
  25.        
  26.         throw new Exception('No existe esta propiedad');
  27.     }
  28.    
  29.     public function save() {
  30.         $conn = mysqli_connect(self::$server, self::$user, self::$pass, self::$dbname);
  31.        
  32.         $query = 'INSERT INTO person (name, position, salary) VALUES (?,?,?)';
  33.         $stmt = mysqli_prepare($conn, $query);
  34.         mysqli_stmt_bind_param($stmt, 'ssd', $this->name, $this->position, $this->salary);
  35.         mysqli_stmt_execute($stmt);
  36.    
  37.         $affected_rows = mysqli_stmt_affected_rows($stmt);                
  38.    
  39.         $stmt->close();
  40.         $conn->close();
  41.    
  42.         return $affected_rows;
  43.     }
  44. }
Creas tu formulario y registras los datos de la siguiente forma (resumida):
Código PHP:
Ver original
  1. $_POST = [
  2.     'name' => 'Enrrique Martinez',
  3.     'position' => 'Jr Developer',
  4.     'salary' => 1024,
  5. ];
  6.  
  7. $employee = new Employee;
  8. $employee->name = $_POST['name'];
  9. $employee->position = $_POST['position'];
  10. $employee->salary = $_POST['salary'];
  11. $enployee->save();
Hasta este punto queda resuelto el problema y funciona, pero no refleja exactamente lo que te pidieron, y comienzas a ver tu código y te das cuenta que puedes usar un constructor para simplificar el código y ademas estas mas cercano a lo que pidieron que se agreguen los datos en el momento que se contrata. Asi que agregas el constructor a tu clase:
Código PHP:
Ver original
  1. public function __construct($data) {
  2.         foreach($data as $attribute => $value) {
  3.             $this->{$attribute} = $value;
  4.         }
  5.     }
y cambias la parte de la contratación con el cambio
Código PHP:
Ver original
  1. $_POST = [
  2.     'name' => 'Enrrique Martinez',
  3.     'position' => 'Jr Developer',
  4.     'salary' => 1024,
  5. ];
  6.  
  7. $employee = new Employee($_POST);
  8. $enployee->save();

Mucho mejor verdad ? Pero te diré que falta en este diseño reflejar mejor la solución del problema así que vamos a abstraer mejor las cosas; si te fijas en la vida real no se crea un empleado se contrata, ademas el empleado se promueve de puesto así que diremos que mi abstracción se representa de esta forma:
Código PHP:
Ver original
  1. interface EmployeeInterface {
  2.    
  3.     public static function hire($data);
  4.    
  5.     public function promote($newPosition, $withNewSalary);
  6.    
  7. }
Una interfaz donde el empleado se promueve y se contrata en lugar solo de "instanciarse" asi que implementemos esta abstracción de nuestro problema con los cambios necesarios en nuestra clase Empleado:
Código PHP:
Ver original
  1. class Employee implements EmployeeInterface
  2. {
  3.     private $name;
  4.     private $position;
  5.     private $salary;
  6.  
  7.     private function __construct($data)
  8.     {
  9.         foreach($data as $attribute => $value) {
  10.             $this->{$attribute} = $value;
  11.         }
  12.     }
  13.  
  14.     public static function hire($data)
  15.     {
  16.         return new self($data);
  17.     }
  18.  
  19.     public function promote($newPosition, $withNewSalary)
  20.     {
  21.         $this->position = $newPosition;
  22.         $this->salary = $withNewSalary;
  23.     }
  24.    
  25.     public function __get($attribute) {
  26.         if(property_exists($this, $attribute)) {
  27.             return $this->{$attribute};
  28.         }
  29.        
  30.         throw new Exception('No existe esta propiedad');
  31.     }
  32.    
  33.     public function __set($attribute, $value) {
  34.         if(property_exists($this, $attribute)) {
  35.             $this->{$attribute} = $value;
  36.         }
  37.        
  38.         throw new Exception('No existe esta propiedad');
  39.     }
  40.    
  41.     public function save() {
  42.         $conn = mysqli_connect(self::$server, self::$user, self::$pass, self::$dbname);
  43.        
  44.         $query = 'INSERT INTO person (name, position, salary) VALUES (?,?,?)';
  45.         $stmt = mysqli_prepare($conn, $query);
  46.         mysqli_stmt_bind_param($stmt, 'ssd', $this->name, $this->position, $this->salary);
  47.         mysqli_stmt_execute($stmt);
  48.    
  49.         $affected_rows = mysqli_stmt_affected_rows($stmt);                
  50.    
  51.         $stmt->close();
  52.         $conn->close();
  53.    
  54.         return $affected_rows;
  55.     }
  56. }
Mi formulario para la contratación queda sin cambio pero necesito ajustar la lógica, así que lo hacemos de la siguiente forma:
Código PHP:
Ver original
  1. $_POST = [
  2.     'name' => 'Enrrique Martinez',
  3.     'position' => 'Jr Developer',
  4.     'salary' => 1024,
  5. ];
  6.  
  7. $employee = Employee::hire($_POST);
  8. // si quieres promover al empleado en otro momento
  9. $employee->prmote('Sr Developer', 2048);
  10. $employee->save();
Ahora es mas claro de leer y de entender por tí y tus colaboradores, ademas si tienes que volver a ver el código sera muy claro también para ti saber que esta pasando.
Con cambios mínimos simplificamos el código y a demás hemos hecho un poco mas flexible el código. Y como es esto ?
Sencillo; Ahora imagina que despues de un tiempo de felicidad llega el cliente y te pide que pases todo esto a Laravel y lo primero que puedes pensar es que tienes que hacer todo de nuevo, o posiblemente no?
Ya que tienes una interfaz en tu solución la puedes usar para resolver la implementación, así que puedes tener facilmente un modelo que resuelva esto en Laravel:
Código PHP:
Ver original
  1. class Employee extends Model implements EmployeeInterface {
  2.    
  3.     protected $fillable = ['name', 'position', 'salary'];
  4.    
  5.     public static function hire($data) {
  6.         return self::create($data);
  7.     }
  8.    
  9.     public function promote($newPosition, $withNewSalary)
  10.     {
  11.         $this->position = $newPosition;
  12.         $this->salary = $withNewSalary;
  13.     }
  14.    
  15. }
Ahora si tu lógica original la pasas a un controlador de Laravel todo va a funcionar igual!
Código PHP:
Ver original
  1. $employee = Employee::hire($_POST);
  2. $employee->promote('Sr Developer', 2048);
Ahora solo te falta ajustar el hecho de que en laravel las variable se reciben usando un objeto Request: asi que lo anterior quedara de la siguiente forma
Código PHP:
Ver original
  1. $employee = Employee::hire($request->all());
  2. $employee->promote('Sr Developer', 2048);
Sencillo no lo crees ?

Es importante tomarte siempre un tiempo para diseñar lo que haces de tal forma que puedas hacer cambios futuros sin tener que rehacer todo de nuevo.
En este ejemplo sencillo usar algunos conceptos de POO nos resolvieron el problema pero existen casos que requieren mas, así que te aconsejo que revises sobre estos temas
  • Objeto
  • Clase
  • Abstracción
  • Encapsulamiento
  • Generalización
  • Polimorfismo
y
  • Diseño orientado a objetos
  • Patrones
  • refactorización
  • Pruebas

Para el asunto de interfaces y clases abstractas puedes leer este hilo aquí mismo en el foro: http://www.forosdelweb.com/f18/difer...erfaz-1108350/
Para finalizar te aliento a que experimentes y tengas paciencia crear código legible y bien diseñado lleva su tiempo, y recuerda; piensa en tu diseño sin los detalles de implementación
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #6 (permalink)  
Antiguo 08/04/2018, 04:51
 
Fecha de Ingreso: julio-2008
Mensajes: 241
Antigüedad: 9 años, 9 meses
Puntos: 9
De acuerdo Respuesta: Clases POO. Teoría.

Antes que nada, agradeceros vuestras explicaciones y vuestro tiempo. Estos aportes son lo que hace grande a la comunidad. Lo que buscaba era vuestra forma de trabajar. Estoy comenzando a hacer cosas y siempre me preguntaba si era la manera correcta. Siempre me ha rondado la duda en la cabeza de cómo trabajáis los profesionales con experiencia en vuestro día a día. Formas de hacer la misma cosa hay cientos, pero óptimas y seguras son sólo unas pocas. Es por eso, que considero importante comenzar entendiendo fuertemente la metodología y los conceptos básicos.

Creo que este hilo va a servir de enorme ayuda a todo aquel que como yo esté comenzando con POO.

Al final me he decantado por comenzar con Laravel. Según he leído es el que tiene mejor curva de aprendizaje para novatos. Aunque voy a profundizar encarecidamente en conceptos como los que mencionáis: Abstracción, encapsulamiento, generalización, polimorfismo. Algunos ya los conocía pero de manera muy superficial.

Agradecer nuevamente la ayuda a hss y mortiprogramador. Enormes. Me ha servido de mucha ayuda. Con vuestras explicaciones, google y algunos manuales, tengo camino por recorrer. Muchas gracias y un saludo.
__________________
"La diversidad de opiniones crean una perspectiva capaz de ver todas las caras del objeto"

Última edición por winjose; 09/04/2018 a las 00:15



La zona horaria es GMT -6. Ahora son las 05:27.