parametros funciones php oop class constructor

funciones php parametros



Devolver un valor en la funciĆ³n constructora de una clase (8)

Hasta ahora tengo una clase de PHP con el constructor

public function __construct ($identifier = NULL) { // Return me. if ( $identifier != NULL ) { $this->emailAddress = $identifier; if ($this->loadUser() ) return $this; else { // registered user requested , but not found ! return false; } }

la funcionalidad de loadUser es buscar la base de datos para una dirección de correo electrónico en particular. Cuando configuro el identificador en algunos correos electrónicos, estoy seguro de que no está en la base de datos; el primer IF se pasa, y va al primer ELSE. aquí el constructor debe devolver FALSO; ¡pero en cambio, devuelve un objeto de la clase con todos los valores NULL!

¿Cómo evito esto? Gracias

EDITAR:

Gracias a todos por las respuestas. ¡eso fue bastante rápido! Veo que la forma de OOP es arrojar una excepción. Entonces, uno, mi pregunta cambia eso, ¿qué debo hacer con la excepción? ¡El manual de php.net es bastante confuso!

// Setup the user ( we assume he is a user first. referees, admins are considered users too ) try { $him = new user ($_emailAddress); } catch (Exception $e_u) { // try the groups database try { $him = new group ($_emailAddress); } catch (Exception $e_g) { // email address was not in any of them !! } }


¿Por qué no simplemente pasar los resultados al constructor necesario para construir el objeto, en lugar de tratar de hacer que el constructor falle a veces?

Incluso si pudieras hacerlo fallar a veces, aún necesitarás verificar después de llamar al constructor para asegurarte de que realmente construyó, y en esas líneas, podrías simplemente llamar a -> loadUser () y pasar los resultados al constructor.

Un buen indicio de alguien me dijo: "siempre dale al constructor lo que necesita para construir el objeto, no hagas que vaya a buscarlo".

public function __construct ($emailInTheDatabase, $otherFieldNeeded) { $this->emailAddress = $emailInTheDatabase; $this->otherField = $otherFieldNeeded; }


El constructor se supone que debe crear un objeto. Como en booleanos php no se consideran objetos, la única opción es nulo. De lo contrario, use una solución alternativa, es decir, escriba un método estático que cree el objeto real.

public static function CheckAndCreate($identifier){ $result = self::loadUser(); if($result === true){ return new EmailClassNameHere(); }else{ return false; } }


Estoy realmente sorprendido de que durante 4 años ninguno de los 22 mil espectadores haya sugerido crear un constructor privado y un método que intente crear un objeto como este:

class A { private function __construct () { echo "Created!/n"; } public static function attemptToCreate ($should_it_succeed) { if ($should_it_succeed) { return new A(); } return false; } } var_dump(A::attemptToCreate(0)); // bool(false) var_dump(A::attemptToCreate(1)); // object(A)#1 (0) {} //! new A(); - gives error

De esta forma obtienes un objeto o es falso (también puedes hacer que devuelva nulo). Capturar ambas situaciones ahora es muy fácil:

$user = User::attemptToCreate(''[email protected]''); if(!$user) { // or if(is_null($user)) in case you return null instead of false echo "Not logged."; } else { echo $user->name; // e.g. }

Puedes probarlo aquí: http://ideone.com/TDqSyi

Encuentro que mi solución es más cómoda de usar que arrojando y atrapando excepciones.


Lo mejor que puedes hacer es lo que Steve ha sugerido. Nunca cree constructores que realicen otro trabajo que no sean asignar parámetros de constructor a las propiedades del objeto, tal vez crear algunos predeterminados, pero nada más. Los constructores están destinados a crear un objeto completamente funcional. Tal objeto siempre debe funcionar como se espera después de su instanciación. Un usuario tiene correo electrónico, nombre y probablemente algunas otras propiedades. Cuando desee instanciar un objeto de usuario, dé todas esas propiedades a su constructor. Lanzar excepciones no es una buena manera tampoco. Una excepción debe ser lanzada bajo condiciones excepcionales. Solicitar un usuario por correo electrónico no es nada excepcional, incluso si finalmente se da cuenta de que no existe ese usuario. La excepción podría ser, por ejemplo, si solicita un usuario por correo electrónico = '''' (a menos que sea un estado regular en su sistema, pero la identificación en lugar de sugerir que los correos electrónicos sean nulos en esos casos). Para obtener todas esas propiedades para un objeto de usuario, debe tener un objeto de fábrica (o un repositorio si lo prefiere) (sí, un objeto; es una mala práctica usar estática). El constructor privado también es una mala práctica ( Necesito un método estático de todos modos y como ya dije, la estática es muy mala.

entonces el resultado debería ser algo como esto:

class User { private $name; private $email; private $otherprop; public function __construct($name, $email, $otherprop = null) { $this->name = $name; $this->email = $email; $this->otherprop = $otherprop; } } class UserRepository { private $db; public function __construct($db) { $this->db = $db; //this is what constructors should only do } public function getUserByEmail($email) { $sql = "SELECT * FROM users WHERE email = $email"; //do some quoting here $data = $this->db->fetchOneRow($sql); //supose email is unique in the db if($data) { return new User($data[''name''], $data[''email''], $data[''otherprop'']); } else { return null; } } } $repository = new UserRepository($database); //suppose we have users stored in db $user = $repository->getUserByEmail(''[email protected]''); if($user === null) { //show error or whatever you want to do in that case } else { //do the job with user object }

¿Ver? no statics, no exception, simple constructors y very legible, testable y modificable


Los constructores no obtienen valores devueltos; sirven completamente para crear una instancia de la clase.

Sin reestructurar lo que ya está haciendo, puede considerar usar una excepción aquí.

public function __construct ($identifier = NULL) { $this->emailAddress = $identifier; $this->loadUser(); } private function loadUser () { // try to load the user if (/* not able to load user */) { throw new Exception(''Unable to load user using identifier: '' . $this->identifier); } }

Ahora puede crear un nuevo usuario de esta manera.

try { $user = new User(''[email protected]''); } catch (Exception $e) { // unable to create the user using that id, handle the exception }


No pondría demasiado en la construcción. Debe considerar una función estática que cree el usuario (fábrica) en lugar de poner todo en el constructor. Por lo tanto, aún puede usar su objeto de usuario sin tener que invocar implícitamente la función de carga. Esto te ahorrará dolor.

public function __construct(){} public function setIdentifier($value){ $this->identifier = $value; } public function load(){ // whatever you need to load here //... throw new UserParameterNotSetException(''identifier not set''); // ... // if user cannot be loaded properly throw new UserNotFoundException(''could not found user''); } public static function loadUser($identifier){ $user = new User(); $user->setIdentifier($identifier); $user->load(); return $user; }

Uso de muestra:

$user = new User(); try{ $user->setIdentifier(''identifier''); $user->load(); } catch(UserParameterNotSetException $e){ //... } catch(UserNotFoundException $e){ // do whatever you need to do when user is not found } // With the factory static function: try{ $user2 = User::loadUser(''identifier''); } catch(UserParameterNotSetException $e){ //... } catch(UserNotFoundException $e){ // do whatever you need to do when user is not found }


Un constructor no puede devolver nada más que el objeto que está intentando crear. Si la creación de instancias no se completa correctamente, se quedará con una instancia de clase llena de propiedades NULL , como ha descubierto.

Si el objeto se carga en un estado incompleto o de error, sugeriría establecer una propiedad para indicar eso.

// error status property public $error = NULL; public function __construct ($identifier = NULL) { // Return me. if ( $identifier != NULL ) { $this->emailAddress = $identifier; if (!$this->loadUser() ) { // registered user requested , but not found ! $this->error = "user not found"; } }

Al crear una instancia del objeto, puede verificar si tiene un estado de error:

$obj = new MyObject($identifier); if (!empty($obj->error)) { // something failed. }

Otra (quizás mejor) alternativa es arrojar una excepción en el constructor, y envolver la instanciación en un try/catch .


gracias por todos los comentarios y soluciones. esto es lo que hice para solucionar el problema: (espero que ayude a los demás)

// Setup the user ( we assume he is a user first. referees, admins are considered users too ) try { $him = new user ($_emailAddress); // check the supplied password $pass_ok = $him->auth($_Password); // check the activation status $active_ok = $him->makeActive(); } catch (Exception $e_u) { // try the groups database try { $him = new group ($_emailAddress); // check the supplied password $pass_ok = $him->auth($_Password); //var_dump ($pass_ok); // check the activation status $active_ok = $him->makeActive(); } catch (Exception $e_g) { // email address was not in any of them !! $pass_ok = false; $active_ok = false; } }