Foros del Web » Programando para Internet » PHP » Frameworks y PHP orientado a objetos »

Para el foro

Estas en el tema de Para el foro en el foro de Frameworks y PHP orientado a objetos en Foros del Web. Hola a todos, quisiera hacer una aportación, solo espero y esté bien, y de una vez ponerlo en las FAQ's. Se trata de una clase ...
  #1 (permalink)  
Antiguo 18/12/2004, 13:21
Avatar de lado2mx
Colaborador
 
Fecha de Ingreso: agosto-2001
Ubicación: Veracruz
Mensajes: 3.720
Antigüedad: 23 años, 4 meses
Puntos: 9
Para el foro

Hola a todos, quisiera hacer una aportación, solo espero y esté bien, y de una vez ponerlo en las FAQ's.

Se trata de una clase en la cual se ponga la consulta, manipulación y resultados de una base de datos en MySQL.

Para varios expertos es relativamente sencillo, pero ya que estamos en un foro donde varios son novatos, se vale compartir.

El problema está es que no he intentado probar este código, y quisiera que le metan mano para ver que se puede mejorar o empeorar.

Cuando esté terminado y corregido, les diré como se puede hacer para que la consulta sea totalmente explicada.

La ventaja es que la hice en español, algunas cosas, pero lo suficiente para que algunos entiendan este bonito objeto.

Saludos, y echenle coco!
Código PHP:
<? 
 
class Base_datos {
     function 
conexion() { 
         
$bd_datos=$this->bd_datos;
         
$bd_host="localhost";
         
$bd_usuario="usuario";
         
$bd_password="password";
         
$conexion=mysql_connect($bd_host$bd_usuario$bd_password);
         IF (
mysql_error()) { echo "Error de conexión: ".mysql_error(); }
         
$conexion_bd=mysql_select_db($bd_datos);
         return 
$conexion;
         return 
$conexion_bd;
     }
     function 
consulta() {
         
$consulta_sql=$this->consulta_sql;
         
$conexion=$this->conexion;
         return 
mysql_query($consulta_sql$conexion) or die (mysql_error());
     }
     function 
num_resultado() {
         
$consultando=$this->consultando;
         return 
mysql_num_rows($consultando$conexion) or die (mysql_error());
     }
     function 
variables() {
         
$consultando=$this->consultando;
         return 
mysql_fetch_array($consultando$conexion) or die (mysql_error());
     }
     function 
cadenas() {
         
$consultando=$this->consultando;
         return 
mysql_fetch_row($consultando$conexion) or die (mysql_error());
     }    
     function 
objetos() {
         
$consultando=$this->consultando;
         return 
mysql_fetch_object($consultando$conexion) or die (mysql_error());
     }
 
?>
  #2 (permalink)  
Antiguo 18/12/2004, 21:00
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 23 años
Puntos: 129
Como comentas que el pùblico de esta classe (o "capa de abstracción" de BD) es para el "principiante" ... Deberìas poner el còdigo de ejemplo de uso de tu classe (objeto); donde lo instancies y uses algunos o todos los mètodos que contiene tu clase.

Fuera de eso .. te hago un comentario simple:

Tu "classe" apenas implementa ningùn método que se salga algo de lo que ya hacen las funciones clásicas de Mysql de por sí. Es cierto que usar la filosofìa de "objeto" te va a permitir por ejemplo instanciar varias veces tu objeto para hacer por ejemplo dos conexiones a dos BD y trabajar con ambas sin los lios de los "links de conexiòn" que suele ocurrir si no se usa un objeto y se usan las funciones nativas de Mysql (o la BD que corresponde). Al hilo de esto y para darle mas "sentido" a un classe/objeto de este tipo .. Estaría bueno poder "extender" tu objeto (classe) como para poder hacer una real "capa de abstracciòn de BD" que pueda trabajar con N Base de datos .. no sólo una (Mysql en tu caso) sino algunas màs (PostgreSQL, .. etc).

De todas formas .. tu classe .. como ejemplo de "encapsulamiento" de unas funcionas para convertilo en "classe" está bien (salvo que algo no sea correto en tu código . .no es mi fuerte la POO asì que sòlo opino como "usuario" posible de una classe como la que has diseñado).

Algunas otras sugerencias .. implementar un control de errores con un método .. como para poder decidir si "mostrar" o no los mensajes de error que puedan ocurrir (o hasta hacer un log ..) Si hay método y definiciòn de este que lo haga se podría implementar por parte del "usuario" de ese objeto que tipo de "log" hacer o que hace con eso ...

Un saludo,
  #3 (permalink)  
Antiguo 19/12/2004, 19:58
Avatar de jpinedo
Colaborador
 
Fecha de Ingreso: septiembre-2003
Ubicación: Lima, Perú
Mensajes: 3.120
Antigüedad: 21 años, 3 meses
Puntos: 41
Algunas opiniones...
- Para que realmente pueda ser útil y flexible... no debes asignar valores a los parámetros de conexión (user, pasword, etc) dentro de la clase... sino que deben ser pasados como parámetros (al constructor o al método correspondiente) desde fuera.

- No declaras las variables de la clase (atributos) y sinembargo las utilizas ($this->consulta_sql, $this->bd_datos)... primero debes declararlas.... además debes dar una vía de acceso (método) para que esas variables puedan tomar un valor.

- Trata de hacer pruebas siempre antes porque hay muchísimas cosas que el simple parser hubiera podido advertirte.

Saludos
  #4 (permalink)  
Antiguo 20/12/2004, 07:03
Avatar de Calisco  
Fecha de Ingreso: marzo-2004
Ubicación: Neuquen
Mensajes: 732
Antigüedad: 20 años, 9 meses
Puntos: 4
Bueno, continuando con lo que te decia JPinedo, deberias declarar los atributos como asi tambien (pienso que es recomendable) los metodos correspondientes para acceder/asignar a los mismos sin romper el encapsulamiento.

Una forma elegante de hacerlo que me han enseñado es mediante un mismo metodo.

Supongamos que declaras la propiedad $bd_datos;

Código PHP:
var $bd_datos
y para manipular la propiedad utilizamos el siguiente metodo:

Código PHP:
function Prp_bd_datos () 
    { 
    switch (
func_num_args()) 
        { 
            case 
1
                
$this->Prp_bd_datoss func_get_arg(0); 
            case 
0
                return 
$this->Prp_bd_datos
        }   
// End Switch 
    
}   // End Metodo 
Ahora, si queremos asignar el valor "Mercado" a la propiedad $bd_datos lo hacemos <? $Objeto->Prp_bd_datos ('Mercado') ?>.
Ahora, si queremos saber cual es el valor de la propiedad lo hacemos sin pasarle argumento al metodo; esto es <? echo $Objeto->Prp_bd_datos ()>.
__________________
| Cabeza De Raton |
  #5 (permalink)  
Antiguo 20/12/2004, 09:07
Avatar de lado2mx
Colaborador
 
Fecha de Ingreso: agosto-2001
Ubicación: Veracruz
Mensajes: 3.720
Antigüedad: 23 años, 4 meses
Puntos: 9
Código PHP:
function Prp_bd_datos ()
{
switch (
func_num_args())
{
case 
1:
$this->Prp_bd_datoss func_get_arg(0);
case 
0:
return 
$this->Prp_bd_datos;
// End Switch
// End Metodo 
En esto no lo entiendo, en que caso específico puede caer en la consulta.

Por cierto, existen errores en la bd. Pero ahora se resuelven:
Código PHP:
<?
class Base_datos {
function 
conexion() {
$bd_datos=$this->bd_datos;
$bd_host=$this->bd_host;
$bd_usuario=$this->bd_usuario;
$bd_password=$this->bd_password;
$conexion=mysql_connect($bd_host$bd_usuario$bd_password);
IF (
mysql_error()) { echo "Error de conexión: ".mysql_error(); }
$conexion_bd=mysql_select_db($bd_datos);
return 
$conexion;
return 
$conexion_bd;
}
function 
consulta() {
$consulta_sql=$this->consulta_sql;
$conexion=$this->conexion;
return 
mysql_query($consulta_sql$conexion) or die (mysql_error());
}
function 
num_resultado() {
$consultando=$this->consultando;
return 
mysql_num_rows($consultando$conexion) or die (mysql_error());
}
function 
variables() {
$consultando=$this->consultando;
return 
mysql_fetch_array($consultando$conexion) or die (mysql_error());
}
function 
cadenas() {
$consultando=$this->consultando;
return 
mysql_fetch_row($consultando$conexion) or die (mysql_error());

function 
objetos() {
$consultando=$this->consultando;
return 
mysql_fetch_object($consultando$conexion) or die (mysql_error());
} } 
?>

Última edición por lado2mx; 20/12/2004 a las 09:16
  #6 (permalink)  
Antiguo 20/12/2004, 14:02
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 23 años
Puntos: 129
mm .. Otra observación ...

A nivel de un objeto .. suele quedar "feo" que este entregue una salida directa. Es altamente recomendable que te hagas un método para que sea ese el que devuelva el error .. no directamente .. es decir:

No hacer:
IF (mysql_error()) { echo "Error de conexión: ".mysql_error(); }

sino algo tipo:
IF (@mysql_error()) { $this->error= "Error de conexión: ".mysql_error(); }

y algún método tipo

function ver_errores(){
return $this->error;
}

para poder llamar al mensaje de error si lo quiero tipo:

echo $db->ver_errores();

Bueno .. algo más elaborado y como corresponda en la classe ese código .. pero por ahí va el tema.

Nota: .. uso el @ delante de la función que podría provocar algún error para que PHP no me muestre sus errores sino que sea mi rutina la que lo haga a mi modo.

Un saludo,

Última edición por Cluster; 20/12/2004 a las 14:03
  #7 (permalink)  
Antiguo 20/12/2004, 17:39
Avatar de sism82  
Fecha de Ingreso: octubre-2003
Ubicación: Guadalajara
Mensajes: 865
Antigüedad: 21 años, 2 meses
Puntos: 1
Esta clase me sirvió para mis propósitos durante un tiempo que use sqlite, se puede cambiar facilmente para ser usada con mysql. Espero te sirva para darte una guía

Código PHP:
<?php
/********************* dbLink ******************/
/*
this class make all the querys to the database
*/
class dbLink {

    public static 
$data_type          = array();
    public static 
$codes                = array();
    public          
$errors               = array();
    public          
$query_resource false;
    public static 
$linkId                false;
    public          
$dbName            '/var/log/asterisk/cdr.db';
    public          
$logFile               '/var/log/asterisk/econovoice/database.iss';    
    
    
    public function 
__construct() {
        
//sets the time header format, and other info stuff
        
$this->dateHeader date('[Y - m - d / H : i : s]')."\n";
        
$this->document   $_SERVER['PHP_SELF'];
                
        
//set the error codes
        
$this->codes['errors']    = array();
        
$this->codes['errors'][0] = 'Sin errores.';
        
$this->codes['errors'][1] = 'No fu&eacute; posible realizar la conexi&oacute;nn a la base de datos. Revise su configuraci&oacute;n.';
        
$this->codes['errors'][2] = 'No fu&eacute; posible abrir el archivo "database.iss". Contacte a soporte t&eacute;cnico.';
        
$this->codes['errors'][3] = 'No fu&eacute; posible escribir el archivo "database.iss". Contacte a soporte t&eacute;cnico.';
        
$this->codes['errors'][4] = 'No fu&eacute; posible consultar la base de datos. Contacte a soporte t&eacute;cnico.';
        
        
//set database types regular expressions
        
$this->data_type['NUM']    = '[0-9]+|[0-9]\.[0-9]+';
        
$this->data_type['TXT']    = '.*';
        
$this->data_type['EMAIL']  = '^[0-9a-z\.\_\-]+@[0-9a-z\.\_\-]+(\.[a-z])*$';
        
$this->data_type['PHONE']  = '^[0-9\(\)\-]+$';
        
$this->data_type['DATE']   = '^[0-9]{4}[\-/][0-9]{2}[\-/][0-9]{2}$';
        
$this->data_type['PASS']   = '^.{6,15}$';
        
$this->data_type['ARRAY']  = '^.*$';
        
        
//open the database connection
        
$this->connect2DB();
        return 
true;
    }
    
    
//make the connection
    
public function connect2DB($db "") {
        
$log  = array();
        
$db   $db == "" $this->dbName $db;
        
$link file_exists($db) ? @sqlite_open($db) : false;
        if ( 
$link ) {
            
$this->linkId $link;
            return 
true;
        } else {
                
$this->errors[] = 1;
                
$log['error'] = $this->codes['errors'][1];
                
$this->writeLog($log);
                return 
false;
        }
    }
    
    
//make a query
    
public function sqlQuery($sql) {
        
$sql  get_magic_quotes_gpc() === $sql addslashes($sql);
        
$rss  = @sqlite_query($this->linkId,$sql);
        if ( 
$rss !== false ) {
            
$this->query_resource $rss;
            return 
$rss;
        } else {
            
$error_code      = @sqlite_last_error($this->linkId);
            
$this->errors[]  = 4;
            
$log['SQLQuery'] = $sql;
            
$log['SQLCode']  = $error_code;
            
$log['SQLError'] = @sqlite_error_string($error_code);
            
$this->writeLog($log);
            return 
false;
        }
    }
    
    
//get the last query data
    
public function getRssData($rss false) {
        
$rss $rss !== false $rss $this->query_resource;
        if ( 
$rss === false ) {
            return 
false;
        } else {
            
$obj = @sqlite_fetch_object($rss);
            return 
is_object($obj) ? $obj false;
        }
    }
    
    
//get the rows of the last query
    
public function getRowsNumber($rss false) {
        
$rss $rss !== false $rss $this->query_resource;
        if ( 
$rss === false ) {
            return 
false;
        } else {
            return 
sqlite_num_rows($rss);
        }
    }
    
    
//initialize the internal result pointer of the last result, or a specific one
    
public function rewindResults($rss false) {
        
$rss $rss !== false $rss $this->query_resource;
        if ( @
sqlite_rewind($rss) ) {
            return 
true;
        } else {
            return 
false;
        }
    }
    
    
//get the last id of an INSERT query
    
public function getLastId($rss false) {
        
$rss $rss !== false $rss $this->query_resource;
        if ( 
$rss === false ) {
            return 
false;
        } else {
            
$ret sqlite_last_insert_rowid($rss);
            return 
$ret;
        }
    }
    
    
//get the last id of a certain table
    
public function getLastIdFromTable($table,$field 'id') {
        
$sql "SELECT MAX(".$field.") AS lastone FROM ".$table."";
        
$rss sqlite_query($this->linkId,$sql);
        
$obj sqlite_fetch_object($rss);
        return 
$obj->lastone;
    }
    
    
//get a field value
    
public function getFieldValue($field$table$conditions "") {
        
$where $conditions != "" " WHERE ".$conditions "";
        
$sql   "SELECT ".$field." AS returnValue FROM ".$table.$where;
        
$sql   get_magic_quotes_gpc() ? $sql addslashes($sql);
        
$rss   = @sqlite_query($this->linkId,$sql);
        if ( 
$rss !== false ) {
            
$obj   = @sqlite_fetch_object($rss);
            
$value is_object($obj) ? $obj->returnValue false;
            return 
$value;
        } else {
            
$error_code      = @sqlite_last_error($this->linkId);
            
$this->errors[]  = 4;
            
$log['SQLQuery'] = $sql;
            
$log['SQLCode']  = $error_code;
            
$log['SQLError'] = @sqlite_error_string($error_code);
            
$this->writeLog($log);
            return 
false;
        }
    }
    
    
//writes a log if errors in the database querys
    
public function writeLog($logInfo = array()) {
        
$rs = @fopen($this->logFile,'a+');
        if ( 
$rs !== false )  {
            
$log  $this->dateHeader;
            
$log .= "Documento: ".$this->document."\n";
            
$log .= "Error Codes: ".serialize($this->errors)."\n";
            foreach ( 
$logInfo as $var => $value ) {
                
$log .= $var." = ".$value."\n";
            }
            
$log .= "\n\n";
            
$writed = @fwrite($rs,$log);
            if ( 
$writed !== false ) {
                @
fclose($rs);
                return 
true;
            } else {
                
$this->errors[] = 3;
                return 
false;
            }
        } else {
            
$this->errors[] = 2;
            return 
false;
        }
    }
    
    
//there are errors??
    
public function noSqlErrors() {
        if ( empty(
$this->errors) ) {
            return 
true;
        } else {
            return 
false;
        }
    }
    
    
//cut last chars of a string
    
public function stripLastChars($string$offset 2) {
        
$strlen strlen($string);
        
$strcut $strlen $offset;
        
$substr substr($string,0,$strcut);
        return 
$substr;
    }
    
    
//get the string errors
    
public function getLinkErrors() {
        
$error_string "";
        foreach (
$this->errors as $ix => $code ) {
            
$error_string .= '<br /> :: '.$this->codes['errors'][$code].'<br />';
        }
        return 
$error_string;
    }
    
    
//close the connection
    
public function __destruct() {
        @
sqlite_close($this->linkId);
        return 
true;
    }
    
}
?>
  #8 (permalink)  
Antiguo 20/12/2004, 18:00
Avatar de sism82  
Fecha de Ingreso: octubre-2003
Ubicación: Guadalajara
Mensajes: 865
Antigüedad: 21 años, 2 meses
Puntos: 1
como ultima observación, si quieres dar soporte para varias bases de datos puedes usar el módulo dbx de php. Busca info en php.net
  #9 (permalink)  
Antiguo 21/12/2004, 08:25
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 23 años
Puntos: 129
AdoDB también estaría muyyy bien como opción .. y más ahora que tiene versión en "classe" y en "extensión" (compilada para Linux y windows).

Un saludo,
  #10 (permalink)  
Antiguo 22/12/2004, 06:55
Avatar de Reynier  
Fecha de Ingreso: noviembre-2002
Ubicación: Por ahí en algún sitio
Mensajes: 1.844
Antigüedad: 22 años, 1 mes
Puntos: 1
Pues ...

Hummm lado2mx tu clase contiene varios errores y como muchos dicen es algo probre. Yo estuve preguntando en el Foro a los usuarios que era lo que más se hacía al trabajar con BDatos y ellos veían con más dificultad. La cosa es que yo estoy trabajando en el diseño de una clase de BDatos que me permita realizar cosas comunes con todos los SGBD, dígamos por ejemplo los más usados y populares: MySQL, PostgreeSQL, SQLite, MS SQL Server, Oracle. Por ejemplo algunas cosas son comunes en todos: las consultas, la devolución de resultados y todo eso, pero no en todas se trabaja de la misma forma. Por ejemplo el SQL de MS SQL Server no es el mismo en algunas cosas que el MySQL. Otra cosa es que SQL Server permite hacer procedimientos almacenados así como COMMIT y ROLLBACK de transacciones realizadas, cosa que creo MySQL no permitirá hasta que salga su versión 5. No he trabajado nunca con PostgreeSQL, SQLite u Oracle así que tendré que leer un poco más sobre estos SGBD para poder realizar la clase que quiero. Así que todo el que haya tenido alguna idea de algún método necesario para trabajar con BDatos que la plasme aquí que yo anotó y trato de añadirselo a mi clase.

Salu2
__________________
Ing. Reynier Pérez Mira
  #11 (permalink)  
Antiguo 22/12/2004, 07:48
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 23 años
Puntos: 129
Reynier . cuando puedas revisa AdoBD .. una de las cosas que hace para "independizar" al máximo hasta el SQL que debes emplear para usar/migrar tu aplicación sin problemas con una u otra BD, es que dispone de algunos métodos muy concretos como por ejemplo para "paginar" registros .. Como ya conoces Mysql tiene sus sentencias SQL para "limitar" registro (LIMIT) pero MS SQL Server por ejemplo tiene otras sentencias para lo mismo que se usan de distinta forma ..

Por eso si implementas métodos que hagan toda esa conversión y manejo del tema .. las migraciones a otras BD serían directas sin tener que modificar sentencias SQL y código de la aplicación para trabajarlo de distinta forma. También es cierto que si bien sería muy útil trabajar así .. por lo mismo si "migramos" de "lenguaje" todas esas ventajas las perderemos .. Pero en esos casos hay que evaluar que es lo que pretendemos: "que nuestra aplicación en tal lenguaje funcione en X BD diferentes?" o que sea portable a otros "lenguajes"? ...

Un saludo,
  #12 (permalink)  
Antiguo 22/12/2004, 08:02
Avatar de Reynier  
Fecha de Ingreso: noviembre-2002
Ubicación: Por ahí en algún sitio
Mensajes: 1.844
Antigüedad: 22 años, 1 mes
Puntos: 1
Pues ...

Creo que quiero lograr ambos dos Cluster ... Así que espero la ayuda y participación de todos aquellos que quieran aportar algo. Recuerda que esto lo hago para la comunidad y para que sea usado por nosotros mismos, no con fines lucrativos ni nada por el estilo.

Salu2
__________________
Ing. Reynier Pérez Mira
  #13 (permalink)  
Antiguo 22/12/2004, 08:18
 
Fecha de Ingreso: noviembre-2003
Mensajes: 114
Antigüedad: 21 años, 1 mes
Puntos: 0
Con relacion a:

"que nuestra aplicación en tal lenguaje funcione en X BD diferentes?"

Yo siempre he usado la clase de phpBB que tiene esta exelente herramienta, seria bueno mirarsela.

Para esto:

"Como ya conoces Mysql tiene sus sentencias SQL para "limitar" registro (LIMIT) pero MS SQL Server por ejemplo tiene otras sentencias para lo mismo que se usan de distinta forma .."

He notado que usa expresiones regulares.


"...o que sea portable a otros "lenguajes"?.."

Si programamos en PHP es lógico que queramos que sea en php. Mi pregunta, ¿hay alguna forma de crearlo de tal manera que podamos cambiar de lenguaje con facilidad?

Un saludo.
__________________
Soporte y Creaciones PHP-Nuke:
NukeProjects.Net

if($Necesitas=="Ayuda"){
echo "No dudes en pedirla";
}
  #14 (permalink)  
Antiguo 24/12/2004, 07:24
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 23 años
Puntos: 129
Cita:
Si programamos en PHP es lógico que queramos que sea en php. Mi pregunta, ¿hay alguna forma de crearlo de tal manera que podamos cambiar de lenguaje con facilidad?
Pues si .. pero te limitas con el SQL a emplear .. Si "fijas" tu BD a Tal .. puedes cambiar de lenguaje sin problemas, es más .. si usas BD que permitan "store procedures", "triggers" ... es mucho más fácil y menos "traumáticos" los cambios de "lenguaje".

Un saludo,
  #15 (permalink)  
Antiguo 24/12/2004, 08:13
Avatar de Reynier  
Fecha de Ingreso: noviembre-2002
Ubicación: Por ahí en algún sitio
Mensajes: 1.844
Antigüedad: 22 años, 1 mes
Puntos: 1
Pues sip ...

Como bien dice Cluster te limitas con el SQL a emplear. Por ejemplo hay cosas que en MySQL no son las mismas que en SQL Server y me imagino que en Oracle, Postgree SQL y SQLite igual. En MySQL se usa la función RAND() para retornar resultados aleatorios, sin embargo en SQL Server es uniqueidentifier() (creo :X). Esperemos que la versión 5 de MySQL ya nos traiga "Store Procedures", "Triggers" y otras ventajas.

Salu2
__________________
Ing. Reynier Pérez Mira
  #16 (permalink)  
Antiguo 24/12/2004, 12:49
Avatar de jpinedo
Colaborador
 
Fecha de Ingreso: septiembre-2003
Ubicación: Lima, Perú
Mensajes: 3.120
Antigüedad: 21 años, 3 meses
Puntos: 41
ejem..ejem... volviendo al tema y para no dejar "colgado" a lado2mx:
Normalmente definirás accesores (cuando sea necesario) para obtener el valor de algún atributo de la clase, o para asignar/modificar su valor.
Código PHP:
class Ejemplo{
    
// Supongamos que tiene un atributo.
    // Lo declaramos:
    
var atributo1;
    
    
// Ahora, si queremos definir accesores para ese atributo,
    // deberemos definir dos métodos, uno para leer y otro para
    // escribir ese atributo.
    
    // Para leer el valor que tiene el atributo creamos un método
    // Este método no necesita parámetros
    
function obtenerAtributo1(){
        return 
this->atributo1;
    }
    
    
// Para escribir/modificar el valor del atributo1, creamos un método.
    // Este método necesitará que le pasemos como parámetro el valor que
    // debe tomar el atributo.
    
function asignarAtributo1($nuevoValor){
        
this->atributo1 $nuevoValor;
    }
}

// Para utilizar la clase:
$ejemplito = new Ejemplo();
// Le damnos un valor al atributo1
$ejemplito->asignarAtributo1("un valor para el atributo1");
// Imprimimos el valor del atributo:
echo $ejemplito->obtenerAtributo1();// imprimirá "un valor para..." 
En PHP4 todos lo métodos y atributos son públicos... por eso no es necesario definir estos accesores... pues podrías haber hecho directamente:
Código PHP:
$ejemplito = new Ejemplo();
// Le damnos un valor al atributo1
$ejemplito->atributo1 ="un valor para el atributo1";
// Imprimimos el valor del atributo:
echo $ejemplito->atributo1;// imprimirá "un valor para..." 
Pero si entiendes temas de encapsulamiento y de miembros privados... verás que es útil y a veces necesario definir esos accesores. PHP5 ya soporta definición de miembros privados.
.
.
Ahora... el ejemplo que te pusieron de ese método hace exactamente lo mismo que te he explicado... sólo que en lugar de utilizar dos métodos (uno para leer y otro para escribir) utiliza uno sólo que leerá o escribirá según le pases parámetros o no.

Código PHP:
function Atributo1(){
    switch (
func_num_args()){// según la cantidad de parámetros que se hayan pasado
        
case 1:
            
// si se pasó un parámetro se asigna valor (escribir)
            
$this->atributo1 func_get_arg(0);
        case 
0:
            
// Si no se pasó ningún parámetro se lee el valor.
            
return $this->atributo;
    }
}
// Para utilizar la clase:
$ejemplito = new Ejemplo();
// Le damnos un valor al atributo1 (método con parámetros)
$ejemplito->Atributo1("un valor para el atributo1");
// Imprimimos el valor del atributo: (método sin parámetros)
echo $ejemplito->Atributo1();// imprimirá "un valor para..." 
Espero que se haya entendido...

Saludos
  #17 (permalink)  
Antiguo 26/12/2004, 19:54
Avatar de Reynier  
Fecha de Ingreso: noviembre-2002
Ubicación: Por ahí en algún sitio
Mensajes: 1.844
Antigüedad: 22 años, 1 mes
Puntos: 1
Excelente

Excelente explicación jpinedo. Solo me quedó una pequeña duda del último ejemplo que pones:
Código PHP:
$this->atributo1 func_get_arg(0); 
y si en vez de pasar un solo argumento paso más de uno, por ejemplo:
Código PHP:
$ejemplito->Atributo1("1","2","3"); 
como sabría que ese objeto recibío tres parámetros y como los imprimo los tres ??

Salu2
__________________
Ing. Reynier Pérez Mira
  #18 (permalink)  
Antiguo 26/12/2004, 21:26
Avatar de jpinedo
Colaborador
 
Fecha de Ingreso: septiembre-2003
Ubicación: Lima, Perú
Mensajes: 3.120
Antigüedad: 21 años, 3 meses
Puntos: 41
Puedes revisar la documentación en el manual:
http://www.php.net/func-get-arg

Pero para este caso específico que explico, se trata de asignar valor a un atributo... o sea que no tendría mucho sentido pasar tres parámetros al método... porque sólo puede tomar un valor a la vez. Este es el caso de un método simple de acceso a un atributo.

En Java se permite que varios métodos compartan el mismo nombre pero con diferentes tipos o número de parámetros. En PHP no puedes definir dos métodos/funciones con el mismo nombre. Para eso viene muy bien funciones como func_num_args() y func_get_arg().

Ahora, podría existir un caso en el que para asignar valor a un taributo tengas que pasar más de un parámetro. Pero en caso de métdos de acceso será menos frecuente.
Código PHP:
class Ejemplo{
    var 
atributo1;
    function 
Atributo1(){
        switch (
func_num_args()){// según la cantidad de parámetros que se hayan pasado
            
case 3:
                
// supongamos que se requieren tres parámetros numéricos para dar valor al 
                // atributo1 y que el valor que tomará será la suma de los tres parámetros.
                
$this->atributo1 func_get_arg(0) + func_get_arg(1) + func_get_arg(2);
                break;
            default:
                
// si se pasa otra cantidad de parámetros, se devuelve el valor.
                // normalmente no se pasará ninguno.
                
return $this->atributo;
        }
    }
}

// Para utilizar la clase:
$ejemplito = new Ejemplo();
// Le damnos un valor al atributo1
$ejemplito->Atributo1(17,13,10); // atributo1 quedará con valor = 40; (la suma)
// Imprimimos el valor del atributo:
echo $ejemplito->Atributo1();// imprimirá: 40 
Como puedes ver... para acceder a los parámetros de la función se utiliza func_num_args() con un índice numérico análogo al de un array.

Saludos
  #19 (permalink)  
Antiguo 27/12/2004, 14:06
Avatar de shinblood  
Fecha de Ingreso: diciembre-2003
Ubicación: lima
Mensajes: 214
Antigüedad: 21 años
Puntos: 1
ok jpinedo pero si tenemos un atributo que es de tipo array, entonces el metodo que sirve para asignarle valores al atributo debe poder asignarle un valor en cada uno de los indices del array:
Código PHP:
 
var $_variables= array();

    function 
propagar()
    {
        switch(
func_num_args()){
            case 
0:    
            foreach(
$this->_variables as $var
                    
$ret.= "&$var=".$_GET[$var]; 
                return 
$ret
                break; 
            default: 
                for(
$i 0$i func_num_args(); $i++) 
                { 
                    
$this->_variables[] = func_get_arg($i); 
                } 
// for 
                
break; 
        } 
// switch 
        
    
// function 
ejemplo tomado de la clase paginado de webstudio
__________________
saludos :adios:

Última edición por shinblood; 27/12/2004 a las 15:15
  #20 (permalink)  
Antiguo 27/12/2004, 14:45
Avatar de Reynier  
Fecha de Ingreso: noviembre-2002
Ubicación: Por ahí en algún sitio
Mensajes: 1.844
Antigüedad: 22 años, 1 mes
Puntos: 1
A eso me refería pero ...

A eso mismo era lo que me refería pero se puede pasar de esta forma:
Código PHP:
 $ret.= "&$var=".$_GET[$var]; 
como referencia ??

Salu2
__________________
Ing. Reynier Pérez Mira
  #21 (permalink)  
Antiguo 27/12/2004, 15:16
Avatar de shinblood  
Fecha de Ingreso: diciembre-2003
Ubicación: lima
Mensajes: 214
Antigüedad: 21 años
Puntos: 1
Pregunta

Disculpa Reynier no te entendi????????
__________________
saludos :adios:
  #22 (permalink)  
Antiguo 27/12/2004, 21:15
Avatar de jpinedo
Colaborador
 
Fecha de Ingreso: septiembre-2003
Ubicación: Lima, Perú
Mensajes: 3.120
Antigüedad: 21 años, 3 meses
Puntos: 41
shinblood:
Gracias por el ejemplo... creo que termina de ilustrar la idea.

Reynier:
Lo que dices no tiene mucho sentido ahora.... porque las variables sólo existen durante la ejecución del script... Al pasar variables a otro script vía GET, estas se crean en ese momento.
Ahora, si poones un ejemplo más concreto o detallas un poco más tu caso... tal vez podríamos entender qué es lo que quieres hacer.

Saludos
  #23 (permalink)  
Antiguo 06/01/2005, 23:31
Avatar de Webstudio
Colaborador
 
Fecha de Ingreso: noviembre-2001
Ubicación: 127.0.0.1
Mensajes: 3.499
Antigüedad: 23 años, 1 mes
Puntos: 69
Bueno muchachos, que alegría que me da y como me halaga que para hacer demostraciones de accessors en PHP para objetos, utilicen las funciones que hice hace ya un par de años ( en realidad, casi 3 ) para la clase Paginado.

Ahora, quería comentarles un par de asuntos, al menos respecto a lo que hago yo con los accessors, para ver si logramos que el tema quede un poco más claro para el que no comprende aún como funciona este "estilo" de funciones:

Una sola variable por Atributo

Este es el caso más común y el explicado por jpinedo. Es el método que espera una y solo una variable para asignarse al atributo. No importa realmente el tipo del atributo, ya sea string, integer, boolean, un arreglo y otro objeto (aqui deberiamos pensar en asignaciones por referencia).
Entonces, el código queda como fue marcado antes:
Código PHP:
function Atributo1(){
    switch (
func_num_args()){// según la cantidad de parámetros que se hayan pasado
        
case 1:
            
// si se pasó un parámetro se asigna valor (escribir)
            
$this->atributo1 func_get_arg(0);
        default:
            
// Si no se pasó ningún parámetro se lee el valor.
            
return $this->atributo;
    }

Por favor noten el detalle que entre 'case 1' y 'default' (aqui he corregido esto, porque no es "case 0", sino que una buena política es que si no tiene la cantidad de argumentos que esperamos, que se comporte como un get), les decía, noten que entre estas dos opciones del switch, no hay un "break". ESto es para que este método se comporte como una asignación de variable normal en PHP, donde luego de la asignación, también se devuelve el valor asignado. Es por eso que podemos hacer cosas como :
Código PHP:
echo $variable 'valor'
Con este método es lo mismo. Se puede hacer normalmente:
Código PHP:
echo $objeto->atributo('valor'); 

Más de una variable en un Accesor.

Aqui no estoy tan seguro de llamar esto un Accessor, porque no es directamente un atributo lo que estamos moficando, sino varios atributos. Si podría llamarse asi si el atributo se compone luego de todos los parámetros de la función. Eso debería verlo cada uno en su implementación o requerimiento particular.
Lo que si, aqui hay que tener en cuenta que es importantísimo que un método de este tipo, requiere SI o SI, X cantidad de argumentos. Ya sean 2, 3, 4 o 1000, el caso es que si se reciben un número inadecuado de parámetros, entonces no hay que hacer nada o actuar como un getter (esto aqui es decisión de cada uno). Por ejemplo:
Código PHP:
function figura()
    switch (
func_num_args()){
        case 
3// un círculo
            
$this->radio func_get_arg(2);
        case 
2// un punto
            
$this->coordX func_get_arg(0);
            
$this->coordY func_get_arg(1);
            return 
true;
            break;
        default:
            
// si se pasa otra cantidad de parámetros, entonces es una llamada inválida.
            
return false;
    }

Aqui vemos como dependiendo de la cantidad de parámetros, se hace una u otra cosa. Si son solo 2 parámetros, se guardan como Coordenadas de un punto, si en cambio son 3 parámetros, aparte se guarda el radio del círculo, si se pasan 1 o más de 3 parámetros, no se hace nada y la aplicación continúa sin problema. Se podría lanzar un mensaje de error o un null para distinguir entre una asignación correcta o no.

Una cantidad no predeterminada de parámetros

Este es el último caso de los que se habló aquí, y es cuando un método es tan flexible que recibe una lista de parámetros que se desconoce previamente. Esto se resuelve con otra de las funciones de PHP que permite trabajar con parámetros. Tan solo tenemos que recorrer el arreglo de parámetros que nos devuelve la función func_get_args(), y ya luego guardarlos en un atributo. Supongamos que tenemos el código del primer ejemplo, que acepta 1 solo parámetro, y a este, le agregamos otro método que reciba la lista variable de atributos. Entonces, nos quedaría algo asi:
Código PHP:
function Atributo1(){
    switch (
func_num_args()){// según la cantidad de parámetros que se hayan pasado
        
case 1:
            
// si se pasó un parámetro se asigna valor (escribir)
            
$this->atributo1 func_get_arg(0);
        default:
            
// Si no se pasó ningún parámetro se lee el valor.
            
return $this->atributo;
    }
}

function 
propagar()
{
    
$this->Atributo1(func_get_args());
}

$obj =& new Objeto();
$obj->propagar('aqui''ponemos''una''lista''de''parámetros');
print_r($obj->Atributo1()): 
De esta manera, veremos como el método Atributo1 nos devuelve un Arreglo con 6 valores, siendo cada uno de ellos los que pasamos al método propagar. Aqui he reutilizado otro método, pero pueden hacer todo el trabajo solo en "propagar" si quieren.



Bueno, eso cubre más o menos mi manera de trabajar con accessors hace ya varios años, y que sigo utilizando hasta en la actualidad en objetos simples. Ya luego si quieren un nivel mayor de complejidad, pueden hacer un Objeto llamado AdministradorAtributos, que contenga una colección de Objetos Atributo y que cada clase que necesiten, extienda o esté compuesta por uno de estas clases. Pero eso ya es otro cantar.
Posiblemente en estos días, les deje un comentario sobre el tema original del tema, que es el de una capa de abstracción de base de datos, la que hice para utilizar, y por qué me parece cómoda, al menos a mi.

Suerte.
__________________
Tutoriales Photoshop | Web-Studio.com.ar
Artículos PHP | ZonaPHP.com

Última edición por Webstudio; 06/01/2005 a las 23:54
  #24 (permalink)  
Antiguo 07/01/2005, 11:09
Avatar de Reynier  
Fecha de Ingreso: noviembre-2002
Ubicación: Por ahí en algún sitio
Mensajes: 1.844
Antigüedad: 22 años, 1 mes
Puntos: 1
Excelente

Excelente explicación WebStudio, eso responde todas mis dudas al respecto.

Salu2 y FELICIDADES a todos los Foreros en este nuevo año.
__________________
Ing. Reynier Pérez Mira
  #25 (permalink)  
Antiguo 07/01/2005, 20:07
Avatar de jpinedo
Colaborador
 
Fecha de Ingreso: septiembre-2003
Ubicación: Lima, Perú
Mensajes: 3.120
Antigüedad: 21 años, 3 meses
Puntos: 41
Otra vez digo.... Qué bueno que has vuelto por acá Webstudio!

Sólo tengo una pequeña duda/comentario:
A partir de PHP5 se puede declarar los métodos como públicos, privados o protegidos.
En este caso si yo quisiera dar acceso únicamente a la lectura de un atributo pero no a su escritura creo que no podría utilizar esta forma de accesores.
Esto porque yo haría un par de declaraciones tipo:
Código PHP:
public function obtenerAtributo(){ 
Código PHP:
private function asignarAtributo(){ 
Y si tuviera un sólo método accesor que se comporta como "getter" o "setter" según los argumentos que se le pasan debería declararlo como "public" ya que quiero que la lectura (getter) sea pública pero esto haría que el "setter" (que es el mismo) quede también "public" y no es lo que quiero.

Claro, para que esto tenga sentido el atributo al que nos referimos, también debehaber sido declarado como "private".

Saludos

Última edición por jpinedo; 07/01/2005 a las 20:29
  #26 (permalink)  
Antiguo 07/01/2005, 23:56
Avatar de Webstudio
Colaborador
 
Fecha de Ingreso: noviembre-2001
Ubicación: 127.0.0.1
Mensajes: 3.499
Antigüedad: 23 años, 1 mes
Puntos: 69
Creo que te estás "haciendo bolas" como dicen en no se donde ( ya no distingo España de México ).
El tema es más o menos así :
Vos querés que un atributo sea de solo lectura? Perfecto, declaron 'private' al atributo.

Luego, solo hacés un método que devuelva el valor del atributo, y a este método, declaralo 'public'. Y ya. Así te asegurás que un atributo es solo lectura.

Con PHP5, sería mejor que nos olvidemos de este tipo de métodos como el que expliqué más arriba, porque ya son innecesarios, habiendo un sistema de Public/private/protected, ahora no es tan "mala praxis" el asignar directamente a un atributo. Además, hay que aprovechar las funciones __set() y __get().

Saludos. !
__________________
Tutoriales Photoshop | Web-Studio.com.ar
Artículos PHP | ZonaPHP.com
  #27 (permalink)  
Antiguo 08/01/2005, 10:36
Avatar de jpinedo
Colaborador
 
Fecha de Ingreso: septiembre-2003
Ubicación: Lima, Perú
Mensajes: 3.120
Antigüedad: 21 años, 3 meses
Puntos: 41
Cita:
Iniciado por Webstudio
Creo que te estás "haciendo bolas"(...)
Pues en realidad creo que las bolas me las hice al tratar de explicarlo
Cita:
Iniciado por Webstudio
(...)Con PHP5, sería mejor que nos olvidemos de este tipo de métodos como el que expliqué más arriba,(...)
Eso es exactamente lo que quería decir, sólo que me extendí un poco tratando de que todos entiendan a qué me refiero.
De todos modos, comparto tu opinión.
Saludos
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta

SíEste tema le ha gustado a 1 personas (incluyéndote)




La zona horaria es GMT -6. Ahora son las 02:38.