Foros del Web » Programando para Internet » PHP »

[SOLUCIONADO] PHP OO array_map() no detecta 2º parametro como array

Estas en el tema de array_map() no detecta 2º parametro como array en el foro de PHP en Foros del Web. Estoy creando una clase para gestionar los emails relacionados con mi blog desde el propio blog. Para poder presentar los mensajes en los buzones necesito ...
  #1 (permalink)  
Antiguo 20/05/2014, 10:27
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
array_map() no detecta 2º parametro como array

Estoy creando una clase para gestionar los emails relacionados con mi blog desde el propio blog.

Para poder presentar los mensajes en los buzones necesito recoger toda la información posible de sus cabeceras. Esto se consigue con imap_headerinfo o con imap_header (imap_headers devuelve muy poca información de cabecera).

imap_headerinfo o su alias imap_header están pensadas para recoger la cabecera de un mensaje referenciado por su número en los parámetros de dichas funciones.

Ante esta limitación, decidí que quería lograr dos cosas con el método de extraer todas las cabeceras de todos los mensajes:

1) código optimizado a ser posible en una sola línea, clara y concisa.

2) a ser posible evitar foreach o cualquier otro loop o condicional.

así que concluí en que debía hacerlo así

Código PHP:
Ver original
  1. public function getAllHeaders(){
  2.         return $this->all_headers=  array_map("\imap_headerinfo", $this->imap_stream, self::search("ALL"));
  3.     }

La idea es sencilla y aparentemente me pareció posible.

self::search() es otro método que utiliza imap_search() para recoger todos los números de los correos de un buzón. El parámetro que le paso "ALL" indica que quiero que recoja todos los los correos en la bandeja; devuelve un array con la siguiente estructura

Cita:
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
Es un array asociativo y bien sencillo.

El problema viene que cuando solicito todas las cabeceras a través de este método (getAllHeaders) me devuelve el siguiente error en array_map()

Cita:
Warning: array_map(): Argument #2 should be an array in C:\xampp\htdocs\xampp\web\pruebas\imap.php on line 114
La línea 114 es la misma del return del método getAllHeaders.

¿Por qué me devuelve ese error si realmente le estoy pasando un array asociativo tal y como especifica la documentación de PHP?
__________________
Ayúdame a hacerlo por mi mismo.
  #2 (permalink)  
Antiguo 20/05/2014, 10:47
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 12 años, 8 meses
Puntos: 292
Respuesta: array_map() no detecta 2º parametro como array

Si el array esta vacio, hay muchas funciones y estructuras de control incluso de PHP que no lo reconocen como array sino directamente NULL

Si is_null o empty() .. no deberias hacer nada o si quieres casting a array

Código PHP:
public function getAllHeaders(){
        return 
$this->all_headers=  array_map("\imap_headerinfo", (array) $this->imap_streamself::search("ALL"));
    } 
No le veo sentido al casting porque esta vacio... pero al menos no explotaria el array_map(), mejor chequea que no este vacio
__________________
Salu2!
  #3 (permalink)  
Antiguo 20/05/2014, 10:59
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

Hola Italico76! gracias por tu ayuda.

Acabo de comprobar otra vez que sea array, no imprimiendo sino que provisionalmente le he añadido un condicional

Código PHP:
Ver original
  1. public function getAllHeaders(){
  2.         $numbers=self::search("ALL");
  3.         if(is_array($numbers))
  4.         return $this->all_headers=  array_map("\imap_headerinfo", $this->imap_stream, $numbers);
  5.     }

Y me sigue devolviendo el mismo error en array_map().

Es decir, sí hay array, y es exactamente el que he mostrado porque también lo he imprimido y me devuelve el mismo error :S
__________________
Ayúdame a hacerlo por mi mismo.
  #4 (permalink)  
Antiguo 20/05/2014, 11:03
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 6 años, 5 meses
Puntos: 379
Respuesta: array_map() no detecta 2º parametro como array

ya verificaste que $this->imap_stream es un array ?
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #5 (permalink)  
Antiguo 20/05/2014, 11:08
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

Hola hhs, $this->imap_stream no es un array, es un stream a un servidor y buzón.

Si le hago un var_dump() me devuelve esto

Cita:
resource(2) of type (imap)
__________________
Ayúdame a hacerlo por mi mismo.
  #6 (permalink)  
Antiguo 20/05/2014, 11:12
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

Vale, acabo de darme cuenta de dónde está mi error. Creía que el argumento 2 se refería al segundo argumento de imap_headerinfo, un error mío, cuando en realidad se refiere al segundo argumento de array_map que en realidad es el primer argumento de headerinfo, es decir, $this->imap_stream.

¿Podría solucionarlo creando un array momentáneo con una clave y como valor $this->imap_stream?

Gracias!
__________________
Ayúdame a hacerlo por mi mismo.
  #7 (permalink)  
Antiguo 20/05/2014, 11:21
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

Finalmente pude solucionar el problema así.

Código PHP:
Ver original
  1. return $this->all_headers=  array_map("\imap_headerinfo", array_fill(0, count($num=self::search("ALL")), $this->imap_stream), self::search("ALL"));

¿Os parece una manera correcta de traer todas las cabeceras de un buzón?

¿Y sino cómo lo haríais?

Gracias por vuestra orientación, a veces mi cabeza se lía sola :D
__________________
Ayúdame a hacerlo por mi mismo.
  #8 (permalink)  
Antiguo 20/05/2014, 15:20
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 6 años, 5 meses
Puntos: 379
Respuesta: array_map() no detecta 2º parametro como array

Algo que hace ruido es que estas usando un arreglo adicional solo para pasar el resource que dicho sea de paso es tantas veces como mensajes tengas. Que sucede si imap_search te devuelve 100 mensajes o mas. Te parece adecuado pasar un arreglo con 100 posiciones para pasar el resource ?
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #9 (permalink)  
Antiguo 20/05/2014, 15:59
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

No me parece óptimo, tienes razón en ello, pero no se me ocurre otra manera para que array_map funcione y pueda tener el código limpio a la vista, o por lo menos esa es la intención :D
__________________
Ayúdame a hacerlo por mi mismo.
  #10 (permalink)  
Antiguo 20/05/2014, 18:37
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 6 años, 5 meses
Puntos: 379
Respuesta: array_map() no detecta 2º parametro como array

Si lo quieres dejar asi, necesitas pensar como pasar el imap resource a imap_headerinfo. por otro lado cual es la razón de de no usar la iteración ?
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #11 (permalink)  
Antiguo 20/05/2014, 19:07
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

Cita:
Iniciado por hhs Ver Mensaje
Si lo quieres dejar asi, necesitas pensar como pasar el imap resource a imap_headerinfo. por otro lado cual es la razón de de no usar la iteración ?
Pienso y no encuentro posibilidad alguna, según la doc de php al respecto de array_map los parámetros para el callback deben ser así. No veo ningún resquicio por donde poder meter el imap_stream.

El motivo es lograr un código fácil de leer, limpio, esto entiendo que implica evitar loops si tengo funciones nativas disponibles que en este caso pueden sustituir un foreach por ejemplo.
__________________
Ayúdame a hacerlo por mi mismo.
  #12 (permalink)  
Antiguo 21/05/2014, 04:30
Avatar de Eleazan  
Fecha de Ingreso: abril-2008
Ubicación: Ibiza
Mensajes: 1.879
Antigüedad: 11 años, 7 meses
Puntos: 326
Respuesta: array_map() no detecta 2º parametro como array

Nunca he usado imap, y puede que meta la pata pero...

Si $this->imap_stream no es un array, ¿pq usas array_map?

¿No sería más sencillo usar imap_headerinfo sin usar array map?
Vamos, digo yo... xD

Edit: Sorry, no habia visto la respuesta con array_fill... Aunq quizás te habria valido sólo con usar imap_headers ;)
__________________
>> Eleazan's Source
>> @Eleazan

Última edición por Eleazan; 21/05/2014 a las 04:38
  #13 (permalink)  
Antiguo 21/05/2014, 04:50
lolainas
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: array_map() no detecta 2º parametro como array

Creo que buscas esta función: function.imap-headers

con lo cual tu línea quedaría mas o menos así:
Código PHP:
Ver original
  1. class MailBox {
  2.  
  3.     private $stream;
  4.  
  5.     function __construct($box, $user, $password) {
  6.         $this->stream = imap_open($box, $user, $password);
  7.     }
  8.  
  9.     function getHeaders() {
  10.         return imap_headers($this->stream);
  11.     }
  12.  
  13. }

EDITO: Acabo de leer que no te sirve imap_headers, perdón!

Código PHP:
Ver original
  1. function getHeaders() {
  2.     return array_map(function($msg) { return imap_header($this->stream, $msg); }, imap_search($this->stream, 'ALL'));
  3. }

Última edición por lolainas; 21/05/2014 a las 05:02
  #14 (permalink)  
Antiguo 21/05/2014, 05:13
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

Gracias Eleazan y lolainas!

Me reté a mi mismo buscar una manera de hacerlo en una sola línea y a ser posible sin loops o condicionales para tener un código limpio, de ahí mi empeño en utilizar llamadas de retorno y creí que con array_map podría hacerlo. El problema es que con array_map los dos argumentos deben ser arrays de la misma longitud para que en cada avance del puntero en cada array realice una operación con cada valor.

Una función nativa que solucione ese problema sería maravilloso :D

lolainas, leo tu edición y el código lo entiendo así:

Un array_map que tiene los siguientes parámetros:

1) una función anónima que tiene un parámetro y retorna imap_header que tiene el stream y $msg, lo que no entiendo es cómo paso $msg a la función anónima.

2) está claro, es un imap_search sin más.
__________________
Ayúdame a hacerlo por mi mismo.
  #15 (permalink)  
Antiguo 21/05/2014, 05:16
lolainas
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: array_map() no detecta 2º parametro como array

$msg es cada valor que devuelve imap_search, osea, un entero (el numero de mensaje)
  #16 (permalink)  
Antiguo 21/05/2014, 05:17
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

Vale ya lo he visto, estaba viendo la funcion anonima como parte del segundo argumento del array_map y no como la llamada de retorno de array_map, mi fault :D

Gracias a todos! ha sido magnífico
__________________
Ayúdame a hacerlo por mi mismo.
  #17 (permalink)  
Antiguo 21/05/2014, 05:20
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

Una pregunta crucial

Entre esta solución

Código PHP:
Ver original
  1. foreach(self::search("ALL") as $msg_number){$headers[]=\imap_headerinfo($this->imap_stream, $msg_number);}
  2. return $headers;

Y esta otra

Código PHP:
Ver original
  1. return array_map(function($msg) { return imap_header($this->imap_stream, $msg); }, imap_search($this->imap_stream, 'ALL'));

¿Cual utilizaríais preferiblemente?
__________________
Ayúdame a hacerlo por mi mismo.
  #18 (permalink)  
Antiguo 21/05/2014, 06:02
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 12 años, 8 meses
Puntos: 292
Respuesta: array_map() no detecta 2º parametro como array

Algo que he leido por ahi... las funciones array_ map() reduce() etc son propias de la programacion funcional y dan mucha potencia en el sentido de simplificar codigo pero tambien ofuscan bastante el codigo:

La solucion mas "limpia" seria el foreach()
__________________
Salu2!
  #19 (permalink)  
Antiguo 21/05/2014, 06:51
Avatar de Eleazan  
Fecha de Ingreso: abril-2008
Ubicación: Ibiza
Mensajes: 1.879
Antigüedad: 11 años, 7 meses
Puntos: 326
Respuesta: array_map() no detecta 2º parametro como array

Diria que array_map utiliza más memoria que foreach.
__________________
>> Eleazan's Source
>> @Eleazan
  #20 (permalink)  
Antiguo 21/05/2014, 17:08
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 6 años, 5 meses
Puntos: 379
Respuesta: array_map() no detecta 2º parametro como array

Cita:
Iniciado por guardarmicorreo Ver Mensaje
El motivo es lograr un código fácil de leer, limpio, esto entiendo que implica evitar loops si tengo funciones nativas disponibles que en este caso pueden sustituir un foreach por ejemplo.
Que es mas legible ??
Código PHP:
Ver original
  1. foreach(self::search("ALL") as $msg_number){$headers[]=\imap_headerinfo($this->imap_stream, $msg_number);}
  2. return $headers;
  3.  
  4. return array_map(function($msg) { return imap_header($this->imap_stream, $msg); }, imap_search($this->imap_stream, 'ALL'));

Código PHP:
Ver original
  1. foreach(self::search("ALL") as $msg_number)
  2. {
  3.     $headers[] = \imap_headerinfo($this->imap_stream, $msg_number);
  4. }
  5. return $headers;
  6.  
  7. return array_map(
  8.     function($msg) {
  9.         return imap_header($this->imap_stream, $msg);
  10.     },
  11.     imap_search($this->imap_stream, 'ALL')
  12. );

El que tengas tu código en una linea no siempre significa que el código es limpio y legible. Solo es compacto.
De todas formas este tipo de cosas ya es preferencia de cada quien.

En cuanto a que solución usar pues te lo pongo de esta forma ¿Crees que se buena idea usar array_map solo para iterar ? en tu caso el foreach y el array_map estan haciendo lo mismo.

Para terminar si quieres escribir código mas legible hay dos principios que debes de tomar en cuenta:
  • El código debe ser sencillo de entender
  • El código debe de ser escrito para reducir el tiempo que le tomaria a una persona comprenderlo
Las ideas las tome prestadas del libro: The Art of Readable Code que seria buena idea te tomaras un tiempo para leer.
Tambien puedes leer la convención PSR-1 y PSR-2 las cuales aclaro, no estoy siguiendo en mis ejemplos.
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #21 (permalink)  
Antiguo 21/05/2014, 21:00
Avatar de guardarmicorreo  
Fecha de Ingreso: noviembre-2012
Ubicación: Córdoba
Mensajes: 1.153
Antigüedad: 7 años
Puntos: 84
Respuesta: array_map() no detecta 2º parametro como array

Muchas gracias hhs por tu nota final.

Aquí he aprendido varias cosas, es un placer! y disfruto con ello.

Saludos :D
__________________
Ayúdame a hacerlo por mi mismo.

Etiquetas: detecta, parametro
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




La zona horaria es GMT -6. Ahora son las 20:11.