php

PHP – Argumentos de la línea de comandos con getopt y $argv

En este post te voy a mostrar a leer y a parsear los argumentos de la línea de comandos, los mismos que se le pasan a un script de PHP; para ello veremos la variable $argv y la función getopt.

Podemos obtener los argumentos a través de su nombre o a través de su índice en un arreglo; la primera opción es la que nos va a interesar más.

PHP puede ejecutarse en la línea de comandos, y así como cualquier otro programa que se ejecuta por comandos, se le pueden pasar argumentos.

Argumentos de la línea de comandos

Como sabemos, los archivos de PHP pueden ejecutarse desde la terminal. La sintaxis es:

php archivo.php

Y a ese script le podemos pasar argumentos. Por ejemplo:

php archivo.php --nombre="luis"

O algo como:

php archivo.php luis

El número de argumentos puede variar, y los mismos se usan para indicar opciones del programa que usamos.

Acceder a los argumentos por su número

Los argumentos están en la variable $argv en forma de arreglo; y el número de argumentos está en la variable $argc.

Siempre habrá al menos un argumento incluso si el usuario no lo especifica, y es el nombre del archivo.

Es decir, en $argv[0] estará el nombre del script. Y para la siguiente ejecución:

php archivo.php

$argv[0] será igual a archivo.php.

Si pasamos más argumentos (separados por espacios) los mismos serán colocados en ese orden en el arreglo. Veamos un ejemplo:

<?php
echo "Hay $argc argumentos\n";
foreach ($argv as $argumento) {
    echo "Recibido un argumento: $argumento \n";
}
/*
Salida:
Hay 3 argumentos
Recibido un argumento: argumentos.php
Recibido un argumento: Hola
Recibido un argumento: mundo
*/

Así que para validar el número de argumentos podemos usar $argc. Y para acceder a los argumentos, usar $argv[1], $argv[2], etcétera.

PHP y getopt

Hay otra manera más bonita de acceder a los argumentos; y digo bonita porque es más cómoda para nosotros y para quien use nuestro script. Aquí lo explico y dejo ejemplos abajo.

Se trata de la función getopt, la cual devuelve un arreglo de las opciones, dependiendo de las letras que le pasemos.

Es decir, se invoca así:

$argumentos = getopt("a:b::c");

No te preocupes, te lo explico.

La función va a tomar cada letra y la va a tomar como una opción. Pero esa letra tiene 3 significados.

  1. Si tiene dos puntos junto a ella, significa que el argumento tendrá un valor. Por ejemplo, podría ser: php archivo.php -a "valor"
  2. En caso de que tenga dos puntos junto a ella, significa que tendrá un valor opcional. Por ejemplo, podría ser: php archivo.php -b "otro valor opcional"
  3. Finalmente, si no tiene nada junto a ella, significa que es una bandera de y no, o un booleano. Por ejemplo: php archivo.php -c, ya que no lleva valor, solo se indica o no su presencia.

Por cierto, esta función permite también los argumentos largos en forma de arreglo (podría ser php archivo.php --nombre "Luis Cabrera") como segundo argumento, eso lo veremos abajo.

Para saber si el usuario pasó o no pasó los argumentos, usamos isset o empty; es un trabajo con comparaciones y arreglos.

En resumen, las opciones cortas son con un guión y las largas con dos guiones. Ambas opciones soportan la sintaxis de bandera, con valor, o con valor opcional.

Cabe mencionar que en los argumentos con getopt no podemos acceder al nombre del script, pero sí con $argv y esa variable siempre está disponible (o al menor en un escenario común)

Ahora veamos algunos ejemplos.

Ejemplo de getopt

Imaginemos un script para enviar un correo electrónico en donde se debe especificar:

  1. El correo del destinatario
  2. El asunto
  3. El mensaje
  4. Una bandera opcional que indica si el correo debería ser guardado en una base de datos

La forma de invocar al script podría ser así:

# Sin guardar:
php correo.php -d parzibyte@gmail.com -a Ayuda -m "Necesito un poco de ayuda con este script de PHP"
# Guardar
php correo.php -d parzibyte@gmail.com -a Ayuda -m "Necesito un poco de ayuda con este script de PHP" -g

De esta manera podríamos hacer unos fabulosos scripts con PHP y los argumentos de la línea de comandos.

Ahora veamos el script:

<?php
// Recuerda:
// Si tiene : entonces debe tener un valor
// Si tiene :: entonces su valor es opcional
// Si no tiene : ni :: entonces quiere decir que la opción es una bandera, no un valor

// Las opciones son:
// -d destinatario
// -a Asunto del correo
// -m El mensaje del correo
// -g Si se especifica la opción, el correo será guardado
$argumentos = getopt("d:a:m:g");
// Las opciones deben estar establecidas
// Si no, salimos e indicamos el modo de uso
if (
    !isset($argumentos["d"])
    ||
    !isset($argumentos["a"])
    ||
    !isset($argumentos["m"])
) {
    exit("Modo de uso:
-d destinatario
-a Asunto del correo
-m El mensaje del correo
-g Si se especifica la opción, el correo será guardado");
}

// Hasta aquí todas las opciones están bien establecidas
$destinatario = $argumentos["d"];
$asunto = $argumentos["a"];
$mensaje = $argumentos["m"];
$guardar = isset($argumentos["g"]);
echo "Enviar correo" . PHP_EOL;
echo "Destinatario: $destinatario" . PHP_EOL;
echo "Asunto: $asunto" . PHP_EOL;
echo "Mensaje: $mensaje" . PHP_EOL;
echo "¿Guardar?: " . ($guardar ? "Sí" : "No") . PHP_EOL;

La mayor parte del script es validación. Si un dato obligatorio no está establecido, salimos del script e indicamos su forma de uso.

Como ves, las opciones del destinatario, mensaje y asunto son obligatorias con valor, en cambio, la opción de guardar es una bandera (no nos importa su valor, solo comprobamos si existe o no con isset).

Para acceder a los datos accedemos a $argumentos["opción"];

La salida es:

Invocar script de php para demostrar uso de getopt

Usar getopt con argumentos largos

Como lo dije, getopt acepta un segundo argumento en forma de arreglo que indica los argumentos que se pueden pasar de forma larga usando dos guiones.

De este modo podemos hacer nuestros scripts más bonitos, pues las opciones serán más expresivas.

Veamos otro ejemplo que usa getopt de PHP para leer ambas opciones:

<?php
// Recuerda:
// Si tiene : entonces debe tener un valor
// Si tiene :: entonces su valor es opcional
// Si no tiene : ni :: entonces quiere decir que la opción es una bandera, no un valor

// Las opciones son:
// -d destinatario
// -a Asunto del correo
// -m El mensaje del correo
// -g Si se especifica la opción, el correo será guardado
$argumentos = getopt("d:a:m:g", array(
    "destinatario:",
    "asunto:",
    "mensaje:",
    "guardar",
));
// Las opciones deben estar establecidas
// Si no, salimos e indicamos el modo de uso
if (
    !(isset($argumentos["d"]) || isset($argumentos["destinatario"]))
    ||
    !(isset($argumentos["a"]) || isset($argumentos["asunto"]))
    ||
    !(isset($argumentos["m"]) || isset($argumentos["mensaje"]))
) {
    exit("Modo de uso:
-d --destinatario   Correo del destinatario
-a --asunto         Asunto del correo
-m --mensaje        El mensaje del correo
-g --guardar        Si se especifica la opción, el correo será guardado");
}

// Hasta aquí todas las opciones están bien establecidas
$destinatario = isset($argumentos["d"]) ? $argumentos["d"] : $argumentos["destinatario"];
$asunto = isset($argumentos["a"]) ? $argumentos["a"] : $argumentos["asunto"];
$mensaje = isset($argumentos["m"]) ? $argumentos["m"] : $argumentos["mensaje"];
$guardar = isset($argumentos["g"]) || isset($argumentos["guardar"]);
echo "Enviar correo" . PHP_EOL;
echo "Destinatario: $destinatario" . PHP_EOL;
echo "Asunto: $asunto" . PHP_EOL;
echo "Mensaje: $mensaje" . PHP_EOL;
echo "¿Guardar?: " . ($guardar ? "Sí" : "No") . PHP_EOL;

Ahora estamos tomando ambas opciones o tipos de argumentos (si no existe la versión corta, buscamos la larga). Esta manera es más específica y amigable con el usuario final.

La ejecución ahora puede ser usando la opción corta como -d o --destinatario, y lo mismo para los otros argumentos.

php correo2.php --destinatario parzibyte@gmail.com -a Ayuda -m "Necesito ayuda con esta app" --guardar
php correo2.php --destinatario=parzibyte@gmail.com -a Ayuda -m "Necesito ayuda con esta app" --guardar
php correo2.php --destinatario=parzibyte@gmail.com --asunto "Ayuda JS" -m "Necesito ayuda con esta app" --guardar

Al llamarlo se ve la siguiente salida:

Mezclando argumentos en llamada a script de php

Como puedes ver, los argumentos largos pueden ser pasados con un signo de igual, separándolos con un espacio y también encerrando el argumento entre comillas, en caso de que este lleve espacios.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

2 días hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

1 semana hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

1 semana hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

1 semana hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

1 semana hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

1 semana hace

Esta web usa cookies.