TransWikia.com

Devolver objeto exceptuando atributos existentes en objeto original

Stack Overflow en español Asked by ordago on December 9, 2021

Tengo un objeto que representa un usuario:

$user = new stdClass();
$user->id = 1;
$user->name = "John Doe";
$user->pass = "1234";

Quería saber si existe una función en PHP a la que se le pase un objeto y una lista de atributos que queramos "censurar". De tal manera que si llamase a esa hipotética función con estos parámetros:

print_r(funcionXXX($user, ['id', 'pass']));

Obtuviese:

stdClass Object
(
    [name] => John Doe
)

Tengo una implementación propia que parece que funciona correctamente:

function digest($obj, $props) {
        $retval = new stdClass();
        $attrs = get_object_vars($obj);
        foreach ($attrs as $key => $value) {
                if (!in_array($key, $props)) {
                        $retval->$key = $value;
                }
        }
        return $retval;
}

Pero me huele que tiene que haber una función de PHP que ya haga esto. Quería saber si existe esa función para no reinventar la rueda.

EDIT: Dos detalles importantes que no he mencionado:

  • Los objetos de entrada que tengo no están asociados a una clase, son objetos que vienen deserializados de un JSON, y no se adaptan a una estructura de clases que pueda determinar en tiempo de desarrollo. Son objetos cuya estructura solo se puede determinar en tiempo de ejecución, por lo que no puedo crear una jerarquía de clases de tal manera que una clase hija tenga menos atributos que la clase padre.
  • La lista de parámetros a eliminar debe ser también dinámica, es decir, no se de antemano que atributos voy a tener que eliminar, por lo que tiene que ser una variable, cuyo valor igualmente se determina en tiempo de ejecución.

2 Answers

Tal función no existe. Pero puedes crearla fácilmente. Ahora bien, dos soluciones son posibles, todo dependerá de lo que mejor convenga.

Si no interesa guardar el objeto original completo

Podríamos implementar una función que limpie el objeto de aquellas propiedades que no quieres.

function removeProperties($mObject, $mProperties){
    /*
        Recorremos el array de propiedades a eliminar
    */
    foreach ($mProperties as $property){
        /*
            Eliminamos la propiedad con unset
            No hace falta verificar si existe o no
            porque unset no devuelve nada
            observa que en el array puse a propósito una propiedad 'fake'
            y ningún mensaje ni error es levantado
        */
        unset($mObject->$property);
    }
}

Así trabajarás siempre sobre un sólo objeto, sin verte obligado a crear un segundo objeto.

Veamos una prueba:

$user = new stdClass();
$user->id = 1;
$user->name = "John Doe";
$user->pass = "1234";    

removeProperties($user, ['id', 'pass', 'fake']);
var_dump($user);

Salida:

object(stdClass)#1 (1) {
  ["name"]=>
  string(8) "John Doe"
}

Si interesa guardar el objeto original completo

Podrías implementar una función que cree un nuevo objeto, verificando las propiedades a excluir.

function createPartialObject($mObject,$toExclude){
    /*
        Creamos el nuevo objeto
    */
    $newObject = new stdClass();
    /*
        Obtenemos un array con las propiedades del objeto original
        y verificamos cuál de ellas no está en el array de propiedades a excluir
    */
        
    foreach (get_object_vars($mObject) as $k => $v) {
            if (!in_array($k,$toExclude)){
                /*
                    Si la propiedad no está en $toExclude
                    la asignamos a $newObject
                */
                $newObject->$k=$v;
            }
    }
    /*
        Retornamos el nuevo objeto
    */
    return $newObject;
}

Prueba:

$newObject=createPartialObject($user, ['id', 'pass', 'fake']);
var_dump($newObject);

Salida:

object(stdClass)#2 (1) {
  ["name"]=>
  string(8) "John Doe"
}

Aquí $user, no es modificado, sino que se crea un nuevo objeto, solamente con aquellas propiedades de $user que interesan. Si no necesitas más las propiedades a excluir, convendría modificar el objeto original, reservando así más espacio en la memoria.

Answered by A. Cedano on December 9, 2021

Que yo sepa no existe una funcion especifica que filtre como lo quieres. Pero yo opino que tu funcion iba por buen camino, si lo que buscas es crear un nuevo objeto filtrando algunas llaves del viejo objeto. Yo terminaria la funcion asi:

Este es tu objeto:

$user = new stdClass();
$user->id = 1;
$user->name = "John Doe";
$user->pass = "1234";

Hasta aqui el objeto es:

stdClass Object
(
    [id] => 1
    [name] => John Doe
    [pass] => 1234
)

La funcion que crea un nuevo objeto y filtra algunas llaves:

function newObject($object, $except_keys_array){
$object_to_array = get_object_vars($object);
$new_filtered_array = [];
foreach($object_to_array as $key => $value){
   if(!in_array($key, $except_keys_array)){
      $new_filtered_array[$key] = $value;
   }
}
$new_object = (object) $new_filtered_array;
return $new_object;
}

Ahora solo queda llamar la funcion y pasarle el objeto y la lista de las llaves que vas a eliminar del objeto:

$new_user = newObject($user, ['id','pass']); // Esto se parece mucho a la funcion que buscas, en el formato que quieres que exista en php.

Hazte un print_r y veras que tu nuevo objeto new_user es:

stdClass Object
(
    [name] => John Doe
)

Tambien puedes pasarle a la funcion la lista como un arreglo y te da el mismo resultado:

$except_keys = ['id','pass'];
$new_user = newObject($user, $except_keys);

Answered by xelfury on December 9, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP