Skip to content

3. Los fundamentos de PHP

3.1. La estructura de los scripts

Image

3.2. Configuración de PHP

PHP viene preconfigurado mediante un archivo de texto [php.ini]. Todas estas configuraciones se pueden modificar mediante programación. La configuración de PHP influye en gran medida en la ejecución de los scripts. Por lo tanto, es importante conocerla. El siguiente script [phpinfo.php] lo permite:

1
2
3
<?php

phpinfo();

Comentarios

  • línea 3: la función [phpinfo] muestra la configuración de PHP;

Resultados de la ejecución

"C:\myprograms\laragon-lite\bin\php\php-7.2.11-Win32-VC15-x64\php.exe" "C:\Data\st-2019\dev\php7\php5-exemples\exemples\tests\phpinfo.php"
phpinfo()
PHP Version => 7.2.11

System => Windows NT DESKTOP-528I5CU 10.0 build 17134 (Windows 10) AMD64
Build Date => Oct 10 2018 01:57:32
Compiler => MSVC15 (Visual C++ 2017)
Architecture => x64
Configure Command => cscript /nologo configure.js  "--enable-snapshot-build" "--enable-debug-pack" "--with-pdo-oci=c:\php-snap-build\deps_aux\oracle\x64\instantclient_12_1\sdk,shared" "--with-oci8-12c=c:\php-snap-build\deps_aux\oracle\x64\instantclient_12_1\sdk,shared" "--enable-object-out-dir=../obj/" "--enable-com-dotnet=shared" "--without-analyzer" "--with-pgo"
Server API => Command Line Interface
Virtual Directory Support => enabled
Configuration File (php.ini) Path => C:\windows
Loaded Configuration File => C:\myprograms\laragon-lite\bin\php\php-7.2.11-Win32-VC15-x64\php.ini
Scan this dir for additional .ini files => (none)
Additional .ini files parsed => (none)
Done.

La función [phpinfo] muestra aquí más de 800 líneas de configuración. No las comentaremos, ya que la mayoría se refiere a un uso avanzado de PHP. Una línea importante es la línea 13 anterior: indica qué archivo [php.ini] se ha utilizado para configurar el PHP que va a utilizar para ejecutar sus scripts. Si desea modificar la configuración de ejecución de PHP, es este archivo el que debe modificar. En este archivo hay numerosos comentarios que explican la función de las diferentes configuraciones.

3.3. Un primer ejemplo

3.3.1. El código

A continuación, se muestra un programa [bases-01.php] que presenta las primeras características de PHP.


<?php

// esto es un comentario
// variable utilizada sin haber sido declarada
$nom = "dupont";
// una visualización en pantalla
print "nom=$nom\n";
// una matriz con elementos de tipo diferente
$tableau = array("un", "deux", 3, 4);
// su número de elementos
$n = count($tableau);
// un bucle
for ($i = 0; $i < $n; $i++) {
  print "tableau[$i]=$tableau[$i]\n";
}
// inicialización de 2 variables con el contenido de una matriz
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// concatenación de las 2 cadenas
$chaine3 = $chaine1 . $chaine2;
// visualización del resultado
print "[$chaine1,$chaine2,$chaine3]\n";
// uso de una función
affiche($chaine1);
// se puede conocer el tipo de una variable
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// el tipo de una variable puede cambiar durante la ejecución
$n = "a changé";
afficheType("n", $n);
// una función puede devolver un resultado
$res1 = f1(4);
print "res1=$res1\n";
// una función puede devolver una matriz de valores
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// se podrían haber recuperado estos valores en una matriz
$t = f2();
for ($i = 0; $i < count($t); $i++) {
  print "t[$i]=$t[$i]\n";
}
// pruebas
for ($i = 0; $i < count($t); $i++) {
  // solo muestra las cadenas
  if (getType($t[$i]) === "string") {
    print "t[$i]=$t[$i]\n";
  }
}
// operadores de comparación == y ===
if("2"==2){
  print "avec l'opérateur ==, la chaîne 2 est égale à l'entier 2\n";
}else{
  print "avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2\n";
}
if("2"===2){
  print "avec l'opérateur ===, la chaîne 2 est égale à l'entier 2\n";
}
else{
  print "avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2\n";
}
// otras pruebas
for ($i = 0; $i < count($t); $i++) {
  // solo muestra los enteros >10
  if (getType($t[$i]) === "integer" and $t[$i] > 10) {
    print "t[$i]=$t[$i]\n";
  }
}
// un bucle while
$t = [8, 5, 0, -2, 3, 4];
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
  print "t[$i]=$t[$i]\n";
  $somme += $t[$i];   //$somme=$somme+$t[$i]
  $i++;               //$i=$i+1
}//mientras
print "somme=$somme\n";

// fin del programa
exit;

//----------------------------------
function affiche($chaine) {
  // muestra $chaine
  print "chaine=$chaine\n";
}

//muestra
//----------------------------------
function afficheType($name, $variable) {
  // muestra el tipo de $variable
  print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}

//afficheType
//----------------------------------
function f1($param) {
  // suma 10 a $param
  return $param + 10;
}

//----------------------------------
function f2() {
  // devuelve 3 valores
  return array("un", 0, 100);
}
?>

Los resultados:


nom=dupont
tableau[0]=un
tableau[1]=deux
tableau[2]=3
tableau[3]=4
[chaine1,chaine2,chaine1chaine2]
chaine=chaine1
type[variable $n]=integer
type[variable $chaine1]=string
type[variable $tableau]=array
type[variable $n]=string
res1=14
(res1,res2,res3)=[un,0,100]
t[0]=un
t[1]=0
t[2]=100
t[0]=un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[2]=100
t[0]=8
t[1]=5
somme=13

Comentarios

  • línea 5: en PHP, no se declara el tipo de las variables. Estas tienen un tipo dinámico que puede variar con el tiempo. $nom representa la variable de identificador «nombre»;
  • línea 7: para escribir en pantalla, se puede utilizar la instrucción print o la instrucción echo;
  • línea 9: la palabra clave array permite definir una matriz. La variable $nom[$i] representa el elemento $i de la matriz $tableau;
  • línea 11: la función count($tableau) devuelve el número de elementos de la matriz $tableau;
  • líneas 13-15: un bucle. Dado que este solo tiene una instrucción, las llaves son opcionales. En el resto de este documento, utilizaremos sistemáticamente las llaves independientemente del número de instrucciones;
  • línea 14: las cadenas de caracteres se escriben entre comillas " o apóstrofos '. Dentro de las comillas, las variables $variable se evalúan, pero no dentro de los apóstrofos;
  • línea 17: la función list permite reunir variables en una lista y asignarles un valor con una única operación de asignación. Aquí $chaine1="cadena1" y $chaine2="cadena2";
  • línea 19: el operador . es el operador de concatenación de cadenas;
  • líneas 83-86: la palabra clave function define una función. Una función devuelve o no valores mediante la instrucción return. El código que la invoca puede ignorar o recuperar los resultados de una función. Una función puede definirse en cualquier parte del código.
  • línea 92: la función predefinida getType($variable) devuelve una cadena de caracteres que representa el tipo de $variable. Este tipo puede cambiar con el tiempo;
  • línea 45: el operador === compara dos elementos de forma estricta: deben ser del mismo tipo para poder compararse. El operador == es menos estricto: dos elementos pueden ser iguales sin ser del mismo tipo. Esto es lo que muestran las instrucciones de las líneas 50-60. En el caso del operador ==, la comparación se realiza tras convertir ambos elementos comparados al mismo tipo. Entonces tienen lugar conversiones implícitas. Es bastante fácil «olvidarse» de la presencia de estas conversiones implícitas y obtener así resultados imprevistos, como descubrir que una condición es verdadera cuando esperabas que fuera falsa. Para evitar este escollo, utilizaremos sistemáticamente el operador de comparación ===;
  • línea 64: también se pueden utilizar los operadores booleanos or y !;
  • línea 69: en lugar de la notación array(), se puede utilizar la notación [] para inicializar una matriz a partir de PHP7;
  • línea 80: la función predefinida exit detiene la ejecución del script;
  • línea 107: la etiqueta ?> indica el final del script PHP. No es imprescindible. Además, en un contexto web, puede plantear problemas si va seguida de espacios o caracteres de fin de línea, difíciles de detectar porque no son visibles en un editor de texto. Por lo tanto, en el resto del documento omitiremos sistemáticamente esta etiqueta;

Nota: en este documento, utilizaremos la palabra clave [print] para mostrar texto en la consola. Otro método para hacer lo mismo es utilizar la palabra clave [echo]. Existen sutiles diferencias entre estas dos palabras clave, pero en el contexto de este documento no habrá ninguna. Por lo tanto, si prefiere utilizar [echo], hágalo.

3.3.2. Uso de Netbeans

Netbeans emite varias advertencias que conviene comprobar. Tomemos como ejemplo el script [bases-01.php]:

Image

En la línea 5, Netbeans emite una advertencia indicando que el archivo no cumple con la recomendación PSR-1 (Recomendaciones estándar PHP n.º 1). Las PSR son recomendaciones para generar código estándar y facilitar así la interoperabilidad y el mantenimiento de códigos escritos por diferentes personas. Puede resultar molesto recibir advertencias si se desea incumplir deliberadamente los estándares, por ejemplo, porque el equipo del proyecto tiene otros. Lo que se desea verificar o no con Netbeans es configurable:

Image

  • en [5], se encuentran los elementos que se quieren controlar con Netbeans;
  • en [6], el nivel de gravedad asignado al error señalado por Netbeans;

Image

En [7] se ve que se ha solicitado comprobar que el código sigue correctamente las recomendaciones PSR-0 y PSR-1. No hay nada obligatorio. Durante la fase de aprendizaje del lenguaje, se recomienda comprobar el máximo de opciones que ofrece Netbeans. Así se aprende mucho. Posteriormente, se adaptará esta comprobación de Netbeans a las normas de codificación del equipo de un proyecto.

Veamos las normas de codificación de PSR-1 y [8, 9]:

Option
Control
  1. Declaración de constantes de clase
Las constantes de clase MUST deben declararse en mayúsculas con separadores de guión bajo.
Ej.: const TAUX_TVA
  1. Declaración de métodos
Los nombres de los métodos MUST deben declararse en camelCase().
Ej.: public function executeBatchImpots{}
  1. Propiedad Name
Los nombres de las propiedades SHOULD deben declararse en el formato $StudlyCaps, $camelCase o $under_score (de forma coherente en un ámbito)
Ej.: public SalaireAnnuel (StudlyCaps), public salaireAnnuel (camelCase), public salaire_annuel (under_score)
  1. Efectos secundarios
Un archivo SHOULD declara nuevos símbolos y no provoca otros efectos secundarios, o bien SHOULD ejecuta lógica con efectos secundarios, pero SHOULD NOT hace ambas cosas.
  1. Declaración de tipos
Los nombres de tipo deben declararse en StudlyCaps (el código escrito para 5.2.x y versiones anteriores utiliza la convención de pseudonamespacing de prefijos en los nombres de tipo). Cada tipo se encuentra en un archivo independiente y está en un espacio de nombres de al menos un nivel: un proveedor de nivel superior name.
Ej.: class EtudiantBoursier {}

La recomendación PSR-1 / 4 establece que en un archivo PHP debe encontrarse:

  • o bien la declaración de un tipo (clases, interfaz);
  • o bien código ejecutable sin declaración de nuevos tipos;

Existen otras recomendaciones PHP no controladas por Netbeans: PSR-3, PSR-4, PSR-6, PSR-7 y PSR-13.

Por comodidad, no todos los ejemplos del documento cumplen la recomendación PSR-1, ya que esto obliga a distribuir el código de las clases e interfaces en archivos separados, lo cual resulta demasiado engorroso para ejemplos básicos. Por lo tanto, es más sencillo ponerlo todo en un solo archivo. Para el ejemplo de la aplicación que sirve de hilo conductor de este documento, se ha intentado cumplir en la medida de lo posible la recomendación PSR-1.

Algunas advertencias de Netbeans señalan un posible error:

Image

La advertencia [Unitialized Variables] indica un error probable, a menudo un error tipográfico en el nombre de una variable. Lo mismo ocurre con la advertencia [Unused Variables].

Por último, se recomienda comprobar todas las advertencias de Netbeans señaladas por un panel en el margen izquierdo del código y un guion amarillo en el margen derecho:

Image

Image

3.4. El ámbito de las variables

3.4.1. Ejemplo 1

El script [bases-02.php] es el siguiente:


<?php

// ámbito de las variables

function f1() {
  // se utiliza la variable global $i
  global $i;
  $i++;
  $j = 10;
  print "f1[i,j]=[$i,$j]\n";
}

function f2() {
  // se utiliza la variable global $i
  global $i;
  $i++;
  $j = 20;
  print "f2[i,j]=[$i,$j]\n";
}

function f3() {
  // se utiliza una variable local $i
  $i = 4;
  $j = 30;
  print "f3[i,j]=[$i,$j]\n";
}

// pruebas
$i = 0;
$j = 0;  // estas dos variables solo son conocidas por una función f
// a menos que esta las declare explícitamente mediante la instrucción global
// que desea utilizarlas
f1();
f2();
f3();
print "test[i,j]=[$i,$j]\n";

Los resultados:

1
2
3
4
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[4,30]
test[i,j]=[2,0]

Comentarios

  • Líneas 29-30: definen las dos variables $i y $j del programa principal. Estas variables no son conocidas dentro de las funciones. Así, en la línea 9, la variable $j de la función f1 es una variable local de la función f1 y es diferente de la variable $j del programa principal. Una función puede acceder a una variable $variable del programa principal mediante la palabra clave global;
  • en la línea 7, la instrucción hace referencia a la variable global $i del programa principal;

3.4.2. Ejemplo 3

El script [bases-03.php] es el siguiente:


<?php

// el ámbito de una variable es global a los bloques de código
$i = 0; {
  $i = 4;
  $i++;
}
print "i=$i\n";

Resultados:

i=5

Comentarios

En algunos lenguajes, una variable definida entre llaves tiene el mismo ámbito que estas: no es conocida fuera de ellas. Los resultados anteriores muestran que esto no es así en PHP. La variable $i definida en la línea 5 dentro de las llaves es la misma que la utilizada en las líneas 4 y 8 fuera de ellas.

3.5. Los cambios de tipo

Las variables en PHP no tienen un tipo constante. Este puede cambiar durante la ejecución según el valor asignado a la variable. En operaciones que implican datos de diversos tipos, el intérprete PHP realiza conversiones implícitas para convertir los operandos a un tipo común. Estas conversiones implícitas, si el desarrollador no las conoce, pueden ser una fuente de errores difíciles de detectar. A continuación se presenta un script [bases-04.php] que muestra conversiones implícitas y explícitas:


<?php

// tipos estrictos en el paso de parámetros
declare(strict_types=1);

// cambios implícitos de tipos
// tipo -->bool
print "Conversion vers un booléen------------------------------\n";
showBool("abcd", "abcd");
showBool("", "");
showBool("[1, 2, 3]", [1, 2, 3]);
showBool("[]", []);
showBool("NULL", NULL);
showBool("0.0", 0.0);
showBool("0", 0);
showBool("4.6", 4.6);

function showBool(string $prefixe, $var) : void {
  print "(bool) $prefixe : ";
  // la conversión de $var a booleano se realiza automáticamente en la prueba siguiente
  if ($var) {
    print "true";
  } else {
    print "false";
  }
  print "\n";
}

Comentarios

  • línea 4: solicita una verificación estricta del tipo de los parámetros de una función cuando este se especifica;
  • línea 18: la función [showBool] tiene como objetivo mostrar la transformación implícita (automática) que realiza el intérprete PHP cuando un valor de cualquier tipo debe transformarse en booleano (línea 21);
  • línea 18: al parámetro $var no se le ha asignado ningún tipo. Por lo tanto, el parámetro efectivo podrá ser de cualquier tipo. El parámetro $prefixe, por su parte, deberá ser de tipo string. La función showBool no devuelve ningún valor (void);
  • línea 21: en la instrucción if($var), el valor de $var debe transformarse en un valor booleano para que se evalúe el if. Sorprendentemente, el intérprete PHP tiene una respuesta para cualquier tipo de valor que se le proporcione;
  • líneas 9-16: el valor del parámetro de la función [showBool] será sucesivamente:
    • línea 9: una cadena no vacía: resultado TRUE (las mayúsculas y minúsculas no importan, TRUE=true);
    • línea 10: una cadena vacía: resultado FALSE;
    • línea 11: una matriz no vacía: resultado TRUE;
    • línea 12: una matriz vacía: resultado FALSE;
    • línea 14: el número real 0: resultado FALSE;
    • línea 15: el número entero 0: resultado FALSE;
    • línea 16: el número real (o entero) distinto de 0: resultado TRUE;

Esto es lo que muestran las pantallas obtenidas:


Conversion vers un booléen------------------------------
(bool) abcd : true
(bool)  : false
(bool) [1, 2, 3] : true
(bool) [] : false
(bool) NULL : false
(bool) 0.0 : false
(bool) 0 : false
(bool) 4.6 : true

Continuemos con el código del script:


//
// cambios implícitos de tipo de string a un tipo numérico
// string --> número
print "Conversion chaîne vers nombre------------------------------\n";
showNumber("12");
showNumber("45.67");
showNumber("abcd");

function showNumber(string $var) : void {
  $nombre = $var + 1;
  var_dump($nombre);
  print "($var): $nombre\n";
}

Comentarios

  • línea 9: la función [showNumber] admite un parámetro de tipo string y no devuelve ningún resultado (void);
  • línea 10: este parámetro se utiliza en una operación aritmética, lo que obligará al intérprete PHP a intentar convertir $var en un número;
    • línea 5: transformará la cadena «12» en el número entero 12;
    • línea 6: convertirá la cadena «45.67» en el número real 45.67;
    • línea 7: emitirá una advertencia, pero transformará de todos modos la cadena «abcd» en el número 0;

Estos son los resultados de la ejecución:

1
2
3
4
5
6
7
8
9
Conversion chaîne vers nombre------------------------------
int(13)
(12): 13
float(46.67)
(45.67): 46.67

Warning: A non-numeric value encountered in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_031.php on line 37
int(1)
(abcd): 1

Continuemos con el código del script:


// cambios explícitos de tipo
// a int
showInt("12.45");
showInt(67.8);
showInt(TRUE);
showInt(NULL);

function showInt($var) : void {
  print "paramètre : ";
  var_dump($var);
  print "\n";
  print "résultat de la conversion : ";
  var_dump((int) $var);
  print "\n";
}

Comentarios

  • línea 21: la función [showInt] recibe un parámetro de cualquier tipo y no devuelve ningún resultado. Intenta convertir el parámetro $var en un entero en la línea 26. En general, para convertir una variable $var en un tipo T, se escribe (T) $var, donde T puede ser: int, integer, bool, boolean, float, double, real, string, array, object, unset;
  • línea 16: convierte la cadena «12.45» en el entero 12;
  • línea 17: convierte el número real 67.8 en el entero 67;
  • línea 18: convierte el booleano TRUE en el entero 1 (el booleano FALSE en el entero 0);
  • línea 19: convierte el puntero NULL en un entero 0;

Esto es lo que muestran las pantallas:

paramètre : string(5) "12.45"

résultat de la conversion : int(12)

paramètre : float(67.8)

résultat de la conversion : int(67)

paramètre : bool(true)

résultat de la conversion : int(1)

paramètre : NULL

résultat de la conversion : int(0)

Continuamos el análisis del script con la conversión explícita de valores al tipo float:


// a float
showFloat("12.45");
showFloat(67);
showFloat(TRUE);
showFloat(NULL);

function showFloat($var) : void {
  print "paramètre : ";
  var_dump($var);
  print "\n";
  print "résultat de la conversion : ";
  var_dump((float) $var);
  print "\n";
}

Comentarios

  • línea 35: la función [showFloat] recibe un parámetro de cualquier tipo y no devuelve ningún resultado;
  • línea 40: el valor de este parámetro se transforma explícitamente en float;
  • línea 30: la cadena «12.45» se transforma en el número real 12.45;
  • línea 31: el entero 67 se transforma en el número real 67;
  • línea 32: el booleano TRUE se transforma en el número real 1 (el valor FALSE en el número 0);
  • línea 33: el puntero NULL se transforma en el número real 0;

Esto es lo que muestran los resultados en pantalla:

paramètre : string(5) "12.45"

résultat de la conversion : float(12.45)

paramètre : int(67)

résultat de la conversion : float(67)

paramètre : bool(true)

résultat de la conversion : float(1)

paramètre : NULL

résultat de la conversion : float(0)

Continuamos con la presentación del script analizando las conversiones al tipo string:


// a string
showstring(5);
showString(6.7);
showString(FALSE);
showString(NULL);

function showString($var) : void {
  print "paramètre : ";
  var_dump($var);
  print "\n";
  print "résultat de la conversion : ";
  var_dump((string) $var);
  print "\n";
}
  • línea 49: la función [showString] recibe un parámetro de cualquier tipo y no devuelve ningún resultado;
  • línea 54: el valor del parámetro se transforma en un tipo string;
  • línea 44: el entero 5 se transformará en la cadena «5»;
  • línea 45: el número real 6,7 se transformará en la cadena «6,7»;
  • línea 46: el booleano FALSE se transformará en una cadena vacía;
  • línea 47: el puntero NULL se convertirá en una cadena vacía;

Estos son los resultados en pantalla:

paramètre : int(5)

résultat de la conversion : string(1) "5"

paramètre : float(6.7)

résultat de la conversion : string(3) "6.7"

paramètre : bool(false)

résultat de la conversion : string(0) ""

paramètre : NULL

résultat de la conversion : string(0) ""

3.6. Las tablas

3.6.1. Matrices clásicas unidimensionales

El script [bases-05.php] es el siguiente:


<?php

// matrices clásicas
// inicialización
$tab1 = array(0, 1, 2, 3, 4, 5);
// recorrido - 1
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// recorrido - 2
print "tab1 a " . count($tab1) . " éléments\n";
reset($tab1);
while (list($clé, $valeur) = each($tab1)) {
    print "tab1[$clé]=$valeur\n";
}
// adición de elementos
$tab1[] = $i++;
$tab1[] = $i++;
// recorrido - 3
print "tab1 a " . count($tab1) . " éléments\n";
$i = 0;
foreach ($tab1 as $élément) {
  print "tab1[$i]=$élément\n";
  $i++;
}
// eliminación del último elemento
array_pop($tab1);
// recorrido - 4
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// eliminación del primer elemento
array_shift($tab1);
// recorrido - 5
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// añadir al final de la tabla
array_push($tab1, -2);
// recorrido - 6
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// Añadir al principio de la tabla
array_unshift($tab1, -1);
// recorrido - 7
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}

Los resultados:


tab1 a 6 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 6 éléments

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_04.php on line 14
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 8 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=7
tab1 a 7 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1 a 6 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1 a 7 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1[6]=-2
tab1 a 8 éléments
tab1[0]=-1
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=-2

Comentarios

El programa anterior muestra operaciones de manipulación de una tabla de valores. Existen dos notaciones para las tablas en PHP:

$tableau=array("un",2,"trois")
$contraires=array("petit"=>"grand", "beau"=>"laid", "cher"=>"bon marché")

La tabla 1 se denomina tabla y la tabla 2, diccionario o tabla asociativa, donde los elementos se anotan clave => valor. La notación $contraires["beau"] designa el valor asociado a la clave «guapo». En este caso, es la cadena «feo». La tabla 1 no es más que una variante del diccionario y podría escribirse así:

$tableau=array(0=>"un",1=>2,2=>"trois")

Así, tenemos $tableau[2] = «tres». En definitiva, solo hay diccionarios. En el caso de una matriz clásica de n elementos, las claves son los números enteros del intervalo [0,n-1].

  • línea 14: la función each($tableau) permite recorrer un diccionario. En cada llamada, devuelve un par (clave, valor) del mismo. Como muestra la línea 10 de los resultados, la función each ha quedado obsoleta en PHP 7;
  • línea 13: la función reset($dictionnaire) coloca la función each en el primer par (clave, valor) del diccionario.
  • línea 14: el bucle while se detiene cuando la función each devuelve un par vacío al final del diccionario. Aquí se produce una conversión implícita: el par vacío se convierte en el valor booleano FALSE;
  • línea 18: la notación $tableau[]=valor añade el elemento valor como último elemento de $tableau;
  • línea 23: la matriz se recorre con un foreach. Este elemento sintáctico permite recorrer un diccionario, y por tanto una matriz, según dos sintaxis:
foreach($dictionnaire as $clé=>$valeur)
foreach($tableau as $valeur)

La primera sintaxis devuelve un par (clave, valor) en cada iteración, mientras que la segunda sintaxis solo devuelve el elemento «valor» del diccionario.

  • línea 28: la función array_pop($tableau) elimina el último elemento de $tableau;
  • línea 35: la función array_shift($tableau) elimina el primer elemento de $tableau;
  • línea 42: la función array_push($tableau,valor) añade valor como último elemento de $tableau;
  • línea 49: la función array_unshift($tableau,valor) añade valor como primer elemento de $tableau;

3.6.2. El diccionario o tabla asociativa

El script [bases-06.php] es el siguiente:


<?php

// diccionarios
$conjoints = ["Pierre" => "Gisèle", "Paul" => "Virginie", "Jacques" => "Lucette", "Jean" => ""];
// recorrido - 1
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
    print "conjoints[$clé]=$valeur\n";
}
// ordenación del diccionario por clave
ksort($conjoints);
// recorrido - 2
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
    print "conjoints[$clé]=$valeur\n";
}
// lista de claves del diccionario
$clés = array_keys($conjoints);
for ($i = 0; $i < count($clés); $i++) {
    print "clés[$i]=$clés[$i]\n";
}
// lista de valores del diccionario
$valeurs = array_values($conjoints);
for ($i = 0; $i < count($valeurs); $i++) {
    print "valeurs[$i]=$valeurs[$i]\n";
}
// búsqueda de una clave
existe($conjoints, "Jacques");
existe($conjoints, "Lucette");
existe($conjoints, "Jean");
// eliminación de una clave-valor
unset($conjoints["Jean"]);
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
foreach ($conjoints as $clé => $valeur) {
  print "conjoints[$clé]=$valeur\n";
}
// fin
exit;

function existe($conjoints, $mari) {
  // comprueba si la clave $mari existe en el diccionario $conjoints
  if (isset($conjoints[$mari])) {
        print "La clé [$mari] existe associée à la valeur [$conjoints[$mari]]\n";
    } else {
        print "La clé [$mari] n'existe pas\n";
    }
}

Los resultados:


Nombre d'éléments du dictionnaire : 4

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_05.php on line 8
conjoints[Pierre]=Gisèle
conjoints[Paul]=Virginie
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle
clés[0]=Jacques
clés[1]=Jean
clés[2]=Paul
clés[3]=Pierre
valeurs[0]=Lucette
valeurs[1]=
valeurs[2]=Virginie
valeurs[3]=Gisèle
La clé [Jacques] existe associée à la valeur [Lucette]
La clé [Lucette] n'existe pas
La clé [Jean] existe associée à la valeur []
Nombre d'éléments du dictionnaire : 3
conjoints[Jacques]=Lucette
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle

Comentarios

El código anterior aplica a un diccionario lo que se ha visto anteriormente para una matriz simple. Solo comentamos las novedades:

  • línea 12: la función ksort (ordenación por clave) permite ordenar un diccionario según el orden natural de la clave;
  • línea 19: la función array_keys($dictionnaire) devuelve la lista de claves del diccionario en forma de matriz;
  • línea 24: la función array_values($dictionnaire) devuelve la lista de valores del diccionario en forma de tabla;
  • línea 43: la función isset($variable) devuelve TRUE si se ha definido la variable $variable; de lo contrario, devuelve FALSE;
  • línea 33: la función unset($variable) elimina la variable $variable.

3.6.3. Las tablas multidimensionales

El script [bases-07.php] es el siguiente:


<?php

// tablas multidimensionales clásicas
// inicialización
$multi = array(array(0, 1, 2), array(10, 11, 12, 13), array(20, 21, 22, 23, 24));
// recorrido
for ($i1 = 0; $i1 < count($multi); $i1++) {
  for ($i2 = 0; $i2 < count($multi[$i1]); $i2++) {
    print "multi[$i1][$i2]=" . $multi[$i1][$i2] . "\n";
  }
}
// diccionarios multidimensionales
// inicialización
$multi = array("zéro" => array(0, 1, 2), "un" => array(10, 11, 12, 13), "deux" => array(20, 21, 22, 23, 24));
// recorrido
foreach ($multi as $clé => $valeur) {
    for ($i2 = 0; $i2 < count($valeur); $i2++) {
        print "multi[$clé][$i2]=" . $multi[$clé][$i2] . "\n";
    }
}

Resultados:


multi[0][0]=0
multi[0][1]=1
multi[0][2]=2
multi[1][0]=10
multi[1][1]=11
multi[1][2]=12
multi[1][3]=13
multi[2][0]=20
multi[2][1]=21
multi[2][2]=22
multi[2][3]=23
multi[2][4]=24
multi[zéro][0]=0
multi[zéro][1]=1
multi[zéro][2]=2
multi[un][0]=10
multi[un][1]=11
multi[un][2]=12
multi[un][3]=13
multi[deux][0]=20
multi[deux][1]=21
multi[deux][2]=22
multi[deux][3]=23
multi[deux][4]=24

Comentarios

  • línea 5: los elementos de la matriz $multi son a su vez matrices;
  • línea 14: la tabla $multi se convierte en un diccionario (clave, valor) donde cada valor es una tabla;

3.7. Las cadenas de caracteres

3.7.1. Notación

El script [bases-08.php] es el siguiente:


<?php

// notación de cadenas
$chaine1 = "un";
$chaine2 = 'un';
print "[$chaine1,$chaine2]\n";
?>

Resultados:

[un,un]

3.7.2. Comparación

El script [bases-09.php] es el siguiente:


<?php

// respeto estricto del tipo de los parámetros de las funciones
declare(strict_types=1);

// función de comparación
function compareModele2Chaine(string $chaine1, string $chaine2): void {
  // compara cadena1 y cadena2
  if ($chaine1 === $chaine2) {
    print "[$chaine1] est égal à [$chaine2]\n";
  } else {
    print "[$chaine1] est différent de [$chaine2]\n";
  }
}

// pruebas de comparación de cadenas
compareModele2Chaine("abcd", "abcd");
compareModele2Chaine("", "");
compareModele2Chaine("1", "");
exit;

Resultados:


[abcd] est égal à [abcd]
[] est égal à []
[1] est différent de []

Comentarios

  • línea 9 del código: se podría haber utilizado el comparador == en lugar de ===. Este último operador es más restrictivo, ya que exige que ambos operandos sean del mismo tipo. Cabe señalar que, en este caso, se podría haber sustituido por el operador ==, ya que el tipo de ambos parámetros está fijado en string en la firma de la función;

3.7.3. Vínculos entre cadenas y matrices

El script [bases-10.php] es el siguiente:


<?php

// cadena a matriz
$chaine = "1:2:3:4";
$tab = explode(":", $chaine);
// recorrido por matriz
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
    print "tab[$i]=$tab[$i]\n";
}
// de matriz a cadena
$chaine2 = implode(":", $tab);
print "chaine2=$chaine2\n";
// añadamos un campo vacío
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// recorrido por la matriz
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
    print "tab[$i]=$tab[$i]\n";
} // ahora tenemos 5 elementos, siendo el último vacío
// añadamos de nuevo un campo vacío
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// recorrido por la matriz
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
    print "tab[$i]=$tab[$i]\n";
} // ahora tenemos 6 elementos, siendo los dos últimos vacíos

Resultados:


tab a 4 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
chaine2=1:2:3:4
chaîne=1:2:3:4:
tab a 5 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
chaîne=1:2:3:4::
tab a 6 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
tab[5]=

Comentarios

  • línea 5: la función explode($séparateur,$chaine) permite recuperar los campos de $chaine separados por $séparateur. Así, explode(":",$chaine) permite recuperar en forma de matriz los elementos de $chaine que están separados por la cadena ":";
  • línea 12: la función implode($séparateur,$tableau) realiza la operación inversa a la función explode. Devuelve una cadena de caracteres formada por los elementos de $tableau separados por $séparateur;

3.7.4. Las expresiones regulares

El script [bases-11.php] es el siguiente:


<?php

// tipo estricto para los parámetros de las funciones
declare (strict_types=1);

// expresiones regulares en php
// extraer los diferentes campos de una cadena
// el patrón: una secuencia de dígitos rodeada de caracteres cualquiera
// solo queremos recuperar la secuencia de dígitos
$modèle = "/(\d+)/";
// comparamos la cadena con el patrón
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");

// el patrón: una secuencia de dígitos rodeada de caracteres arbitrarios
// queremos la secuencia de números, así como los campos que la preceden y la siguen
$modèle = "/^(.*?)(\d+)(.*?)$/";
// se compara la cadena con el patrón
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");

// el patrón: una fecha en formato dd/mm/aa
$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";
compareModele2Chaine($modèle, "10/05/97");
compareModele2Chaine($modèle, "  04/04/01  ");
compareModele2Chaine($modèle, "5/1/01");

// el patrón: un número decimal
$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";
compareModele2Chaine($modèle, "187.8");
compareModele2Chaine($modèle, "-0.6");
compareModele2Chaine($modèle, "4");
compareModele2Chaine($modèle, ".6");
compareModele2Chaine($modèle, "4.");
compareModele2Chaine($modèle, " + 4");

// fin
exit;

// --------------------------------------------------------------------------
function compareModele2Chaine(string $modèle, string $chaîne): void {
  // compara la cadena $chaîne con el patrón $modèle
  // se compara la cadena con el patrón
  $champs = [];
  $correspond = preg_match($modèle, $chaîne, $champs);
  // visualización de resultados
  print "\nRésultats($modèle,$chaîne)\n";
  if ($correspond) {
    for ($i = 0; $i < count($champs); $i++) {
      print "champs[$i]=$champs[$i]\n";
    }
  } else {
    print "La chaîne [$chaîne] ne correspond pas au modèle [$modèle]\n";
  }
}

Resultados:


Résultats(/(\d+)/,xyz1234abcd)
champs[0]=1234
champs[1]=1234

Résultats(/(\d+)/,12 34)
champs[0]=12
champs[1]=12

Résultats(/(\d+)/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/(\d+)/]

Résultats(/^(.*?)(\d+)(.*?)$/,xyz1234abcd)
champs[0]=xyz1234abcd
champs[1]=xyz
champs[2]=1234
champs[3]=abcd

Résultats(/^(.*?)(\d+)(.*?)$/,12 34)
champs[0]=12 34
champs[1]=
champs[2]=12
champs[3]= 34

Résultats(/^(.*?)(\d+)(.*?)$/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/^(.*?)(\d+)(.*?)$/]

Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,10/05/97)
champs[0]=10/05/97
champs[1]=10
champs[2]=05
champs[3]=97

Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,  04/04/01  )
champs[0]=  04/04/01  
champs[1]=04
champs[2]=04
champs[3]=01

Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,5/1/01)
La chaîne [5/1/01] ne correspond pas au modèle [/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/]

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,187.8)
champs[0]=187.8
champs[1]=
champs[2]=187.8

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,-0.6)
champs[0]=-0.6
champs[1]=-
champs[2]=0.6

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4)
champs[0]=4
champs[1]=
champs[2]=4

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,.6)
champs[0]=.6
champs[1]=
champs[2]=.6

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4.)
champs[0]=4.
champs[1]=
champs[2]=4.

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/, + 4)
champs[0]= + 4
champs[1]=+
champs[2]=4

Comentarios

  • Aquí utilizamos expresiones regulares para extraer los distintos campos de una cadena de caracteres. Las expresiones regulares permiten superar las limitaciones de la función implode. El principio consiste en comparar una cadena de caracteres con otra cadena denominada «plantilla» mediante la función preg_match:

$correspond = preg_match($modèle, $chaîne, $champs);

La función preg_match devuelve un valor booleano TRUE si el patrón se encuentra en la cadena. En caso afirmativo, $champs[0] representa la subcadena correspondiente al patrón. Por otra parte, si el patrón contiene subpatrones entre paréntesis, $champs[1] es la parte de $chaîne correspondiente al primer subpatrón, $champs[2] es la parte de $chaîne correspondiente al segundo submodelo, etc.

Consideremos el primer ejemplo. El patrón se define en la línea 10: designa una secuencia de uno o varios (+) dígitos (\d) situados en cualquier lugar de una cadena. Además, el patrón define un subpatrón entre paréntesis;

  • línea 12: el patrón /(\d+)/ (secuencia de uno o más dígitos en cualquier lugar de la cadena) se compara con la cadena «xyz1234abcd». Vemos que la subcadena 1234 se ajusta al patrón. Por lo tanto, tendremos $champs[0] igual a «1234». Por otra parte, el patrón tiene subpatrones entre paréntesis. Tendremos $champs[1] = «1234»;
  • línea 13: el patrón /(\d+)/ se compara con la cadena «12 34». Se observa que las subcadenas 12 y 34 coinciden con el patrón. La comparación se detiene en la primera subcadena que coincide con el patrón. Por lo tanto, tendremos $champs[0]=12 y $champs[1]=12;
  • línea 14: el patrón /(\d+)/ se compara con la cadena «abcd». No se encuentra ninguna coincidencia;

Explicaremos los patrones utilizados en el resto del código:


$modèle = "/^(.*?)(\d+)(.*?)$/";

corresponde al inicio de la cadena (^), seguido de 0 o más (*) caracteres cualquiera (.), luego 1 o más (+) dígitos, y de nuevo 0 o más (*) caracteres cualquiera (.). El patrón (.*) designa 0 o más caracteres cualquiera. Un patrón de este tipo coincidirá con cualquier cadena. Por lo tanto, el patrón /^(.*)(\d+)(.*)$/ nunca se encontrará, ya que el primer subpatrón (.*) absorberá toda la cadena. El patrón (.*?)(\d+) designa 0 o más caracteres cualquiera hasta el siguiente subpatrón (?), en este caso \d+. Por lo tanto, los dígitos ya no son absorbidos por el patrón (.*). El patrón anterior se corresponde, por tanto, con [début de chaîne (^), une suite de caractères quelconques (.*?), une suite d'un ou plusieurs chiffres (\d+), une suite de caractères quelconques (.*?), la fin de la chaîne ($)].


$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";

corresponde a [début de chaîne (^), 2 chiffres (\d\d), le caractère / (\/), 2 chiffres, /, 2 chiffres, une suite de 0 ou plusieurs espaces (\s*), la fin de chaîne ($)].


$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";

corresponde al inicio de la cadena (^), 0 o más espacios (\s*), un signo + o - [+|-] presente 0 o 1 vez (?), una secuencia de 0 o más espacios (\s*), 1 o más dígitos seguidos de un punto decimal seguido de cero o más dígitos (\d+\.\d*) o (|) un punto decimal (\.) seguido de uno o más dígitos (\d+) o (|) uno o más dígitos (\d+), una secuencia de 0 o más espacios (\s*)].

Nota: el término [espace] en las expresiones regulares designa un conjunto de caracteres: espacio, salto de línea \n, tabulación \t, retorno de carro \r, salto de página \f…

3.8. Las funciones

3.8.1. Modo de paso de los parámetros

El script [base-12.php] es el siguiente:


<?php

// modo de paso de parámetros de una función
// respeto estricto del tipo de los parámetros
declare(strict_types=1);

function f(int &$i, int $j): void {
  // $i se obtendrá por referencia
  // $j se obtendrá por valor
  $i++;
  $j++;
  print "f[i,j]=[$i,$j]\n";
}

// pruebas
$i = 0;
$j = 0;
// $i y $j se han pasado a la función f
f($i, $j);
print "test[i,j]=[$i,$j]\n";

Resultados:

f[i,j]=[1,1]
test[i,j]=[1,0]

Comentarios

El código anterior muestra las dos formas de pasar parámetros a una función. Veamos el siguiente ejemplo:

1
2
3
4
5
6
7
function f(&$a,$b){

}

// programa principal
$i=10; $j=20;
f($i,$j);
  • línea 1: define los parámetros formales $a y $b de la función f. Esta manipula estos dos parámetros formales y devuelve un resultado;
  • línea 7: llamada a la función f con dos parámetros efectivos $i y $j. Las relaciones entre los parámetros formales ($a, $b) y los parámetros efectivos ($i, $j) se definen en las líneas 1 y 7:
  • &$a: el signo & indica que el parámetro formal $a tomará como valor la dirección del parámetro efectivo $i. Dicho de otro modo, $a y $i son dos referencias a la misma ubicación de memoria. Manipular el parámetro formal $a equivale a manipular el parámetro efectivo $i. Esto es lo que muestra la ejecución del código. Este modo de paso es adecuado para los parámetros de salida y para datos de gran volumen, como tablas y diccionarios. A este modo de paso se le denomina «paso por referencia».
  • $b: el parámetro formal $b tomará como valor el del parámetro efectivo $j. Se trata de un paso por valor. Los parámetros formales y efectivos son dos variables diferentes. Manipular el parámetro formal $b no tiene ninguna incidencia en el parámetro efectivo $j. Esto es lo que muestra la ejecución del código. Este modo de paso es adecuado para los parámetros de entrada.
  • Consideremos la función de intercambio que admite dos parámetros formales $a y $b. La función intercambia el valor de estos dos parámetros. Así, en una llamada de intercambio ($i,$j), el código llamante espera que se intercambien los valores de los dos parámetros efectivos. Por lo tanto, se trata de parámetros de salida (se modifican). Por lo tanto, se escribirá:
function échange(&$a,&$b){.}

El siguiente script [base-13.php] muestra otros ejemplos:


<?php

// tipos en modo estricto
// declare(strict_types = 1);

// modo de paso de parámetros

function f(&$i, $j) {
  // $i se obtendrá por referencia
  // $j se obtendrá por valor
  $i++;
  $j++;
  print "f[i,j]=[$i,$j]\n";
}

function g(int &$i, int $j) : void {
  // $i se obtendrá por referencia
  // $j se obtendrá por valor
  $i++;
  $j++;
  print "g[i,j]=[$i,$j]\n";
}

// pruebas
$i = 0;
$j = 0;
// $i y $j se pasan a la función f
f($i, $j);
print "test[i,j]=[$i,$j]\n";
// $i y $j se pasan a la función g
g($i, $j);
print "test[i,j]=[$i,$j]\n";
// se pasan parámetros incorrectos a f
$a=5.3;
$b=6.2;
f($a, $b);
print "test[a,b]=[$a,$b]\n";
// se pasan parámetros incorrectos a f
$a=5.3;
$b=6.2;
g($a, $b);
print "test[a,b]=[$a,$b]\n";

Comentarios

  • líneas 8-14: la función f estudiada en el párrafo anterior, pero no se han tipado los parámetros;
  • líneas 16-22: la función g hace lo mismo que la función f, pero se especifica el tipo de los parámetros esperados; esto es una novedad PHP 7. Se esperan dos parámetros de tipo int. Queremos ver qué ocurre cuando el parámetro efectivo pasado a la función no tiene el tipo esperado por esta;
  • líneas 25-26: $i y $j son dos números enteros;
  • líneas 28-29: llamada a la función f con parámetros del tipo esperado;
  • líneas 31-32: llamada a la función g con parámetros del tipo esperado;
  • líneas 34-35: las variables $a y $b son de tipo float;
  • líneas 36-37: llamada a la función f con parámetros que no son del tipo esperado;
  • líneas 41-42: llamada a la función g con parámetros que no son del tipo esperado;

Resultados

1
2
3
4
5
6
7
8
f[i,j]=[1,1]
test[i,j]=[1,0]
g[i,j]=[2,1]
test[i,j]=[2,0]
f[i,j]=[6.3,7.2]
test[a,b]=[6.3,6.2]
g[i,j]=[6,7]
test[a,b]=[6,6.2]
  • las líneas 5-6 muestran que la función f ha aceptado los dos parámetros de tipo float y ha trabajado con ellos;
  • las líneas 7-8 muestran que la función g ha aceptado los dos parámetros de tipo float, pero que los ha transformado en el tipo int (línea 7);

Ahora descomentemos la línea 4:

declare(strict_types = 1);

Esta instrucción indica que deben respetarse los tipos de los parámetros formales. Si no es así, se señala un error. Los resultados de la ejecución pasan a ser entonces:

f[i,j]=[1,1]
test[i,j]=[1,0]
g[i,j]=[2,1]
test[i,j]=[2,0]
f[i,j]=[6.3,7.2]
test[a,b]=[6.3,6.2]

Fatal error: Uncaught TypeError: Argument 1 passed to g() must be of the type integer, float given, called in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php on line 40 and defined in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php:15
Stack trace:
#0 C:\Data\st-2019\dev\php7\php5-ejemplos\ejemplos\ejemplo_111.php(40): g(5.3, 6.2)
#1 {main}
  thrown in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php on line 15
  • líneas 9-10: el intérprete PHP 7 ha lanzado una excepción para indicar que el primer parámetro pasado a la función g no tenía el tipo correcto. Se recomienda ser estricto con los tipos de los parámetros, siempre que sea posible, para detectar errores en las llamadas a funciones;

3.8.2. Resultados devueltos por una función

El script [base-15.php] es el siguiente:


<?php

// tipos en modo estricto
declare(strict_types=1);

// resultados devueltos por una función
// una función puede devolver varios valores en una matriz
list($res1, $res2, $res3) = f1(10);
print "[$res1,$res2,$res3]\n";
$res = f1(10);
for ($i = 0; $i < count($res); $i++) {
  print "f1 : res[$i]=$res[$i]\n";
}

// una función puede devolver un objeto
$res = f2(10);
print "f2 : [$res->res1,$res->res2,$res->res3]\n";
// ¿objeto de qué tipo?
print "nature de l'objet : ";
var_dump($res);
print "\n";

// se hace lo mismo con la función f3
$res = f3(10);
print "f3 : [$res->res1,$res->res2,$res->res3]\n";
// ¿De qué tipo de objeto se trata?
print "nature de l'objet : ";
var_dump($res);
print "\n";

// fin
exit;

// función f1
function f1(int $valeur): array {
  // devuelve una matriz ($valeur+1,$valeur+2,$valeur+3)
  return array($valeur + 1, $valeur + 2, $valeur + 3);
}

// función f2
function f2(int $valeur): object {
  // devuelve un objeto ($valeur+1,$valeur+2,$valeur+3)
  $res->res1 = $valeur + 1;
  $res->res2 = $valeur + 2;
  $res->res3 = $valeur + 3;
  // devuelve el objeto
  return $res;
}

// función f3: hace lo mismo que la función f2
function f3(int $valeur): object {
  // devuelve un objeto ($valeur+1,$valeur+2,$valeur+3)
  $res = new stdclass();
  $res->res1 = $valeur + 1;
  $res->res2 = $valeur + 2;
  $res->res3 = $valeur + 3;
  // devuelve el objeto
  return $res;
}

Resultados


[11,12,13]
f1 : res[0]=11
f1 : res[1]=12
f1 : res[2]=13

Warning: Creating default object from empty value in C:\Data\st-2019\dev\php7\php5-exemples\exemples\bases\base-15.php on line 43
f2 : [11,12,13]
nature de l'objet : object(stdClass)#1 (3) {
  ["res1"]=>
  int(11)
  ["res2"]=>
  int(12)
  ["res3"]=>
  int(13)
}

f3 : [11,12,13]
nature de l'objet : object(stdClass)#2 (3) {
  ["res1"]=>
  int(11)
  ["res2"]=>
  int(12)
  ["res3"]=>
  int(13)
}

Comentarios

  • El programa anterior muestra que una función PHP puede devolver un conjunto de resultados y no uno solo, en forma de matriz u objeto. El concepto de objeto se explica con más detalle más adelante;
  • líneas 35-38: la función f1 devuelve varios valores en forma de matriz (array);
  • líneas 41-48: la función f2 devuelve varios valores en forma de objeto (object);
  • líneas 51-59: la función f3 es idéntica a la función f2, salvo que crea explícitamente un objeto, línea 53;
  • la línea 6 de los resultados emite una advertencia (warning) indicando que PHP se ha visto obligado a crear un objeto por defecto en la línea 43 del código, es decir, al utilizar la notación [$res→res1]. La función var_dump de la línea 20 del código permite acceder a la naturaleza del objeto y a su contenido. En los resultados, vemos que:
    • línea 8: el objeto creado por defecto es de tipo stdClass;
    • líneas 9-10: la propiedad res1 es de tipo entero y tiene el valor 11;
    • etc…
    • para evitar la advertencia de la línea 6 de los resultados, se crea explícitamente, en la línea 53 de la función f3, un objeto de tipo stdClass;

3.9. Los archivos de texto

El script [bases-16.php] es el siguiente:


<?php

// cumplimiento estricto del tipo de los parámetros de las funciones
declare (strict_types=1);

// procesamiento secuencial de un archivo de texto
// este es un conjunto de líneas con el formato login:pwd:uid:gid:infos:dir:shell
// cada línea se introduce en un diccionario con el formato login => uid:gid:infos:dir:shell
// se establece el nombre del archivo
$INFOS = "infos.txt";
// se abre en modo de creación
if (!$fic = fopen($INFOS, "w")) {
  print "Erreur d'ouverture du fichier $INFOS en écriture\n";
  exit;
}
// se genera un contenido arbitrario
for ($i = 0; $i < 100; $i++) {
  fputs($fic, "login$i:pwd$i:uid$i:gid$i:infos$i:dir$i:shell$i\n");
}
// se cierra el archivo
fclose($fic);

// se aprovecha: fgets conserva el marcador de fin de línea
// esto permite no recuperar una cadena vacía al leer una línea en blanco
// se abre en modo lectura
if (!$fic = fopen($INFOS, "r")) {
  print "Erreur d'ouverture du fichier $INFOS en lecture\n";
  exit;
}

// las líneas tienen menos de 1000 caracteres
// la lectura de la línea se detiene en el marcador de fin de línea
// o en el marcador de fin de archivo
while ($ligne = fgets($fic, 1000)) {
  // se elimina el marcador de fin de línea si existe
  $ligne = cutNewLineChar($ligne);
  // se coloca la línea en una tabla
  $infos = explode(":", $ligne);
  // se recupera el nombre de usuario
  $login = array_shift($infos);
  // se omite la contraseña
  array_shift($infos);
  // se crea una entrada en el diccionario
  $dico[$login] = $infos;
}
// se cierra
fclose($fic);

// explotación del diccionario
afficheInfos($dico, "login10");
afficheInfos($dico, "X");

// fin
exit;

// --------------------------------------------------------------------------
function afficheInfos(array $dico, string $clé): void {
  // muestra el valor asociado a la clave en el diccionario $dico si existe
  if (isset($dico[$clé])) {
    // el valor existe: ¿es una matriz?
    $valeur = $dico[$clé];
    if (is_array($valeur)) {
      print "[$clé," . join(":", $valeur) . "]\n";
    } else {
      // $valeur no es una matriz
      print "[$clé,$valeur]\n";
    }
  } else {
    // $clé no es una clave del diccionario $dico
    print "la clé [$clé] n'existe pas\n";
  }
}

// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
  // se elimina el marcador de fin de línea de $ligne si existe
  $L = strlen($ligne);  // longitud de línea
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // fin
  return($ligne);
}

El archivo infos.txt:

1
2
3
4
5
6
login0:pwd0:uid0:gid0:infos0:dir0:shell0
login1:pwd1:uid1:gid1:infos1:dir1:shell1
login2:pwd2:uid2:gid2:infos2:dir2:shell2
login98:pwd98:uid98:gid98:infos98:dir98:shell98
login99:pwd99:uid99:gid99:infos99:dir99:shell99

Los resultados:


[login10,uid10:gid10:infos10:dir10:shell10]
la clé [X] n'existe pas

Comentarios

  • línea 12: fopen(nom_fichier,"w") abre el archivo nom_fichier en modo de escritura (w = write). Si el archivo no existe, se crea. Si existe, se borra su contenido. Si la creación falla, fopen devuelve el valor false. En la instrucción if (!$fic = fopen($INFOS, "w")) {…}, hay dos operaciones sucesivas: 1) $fic=fopen(..) 2) if( ! $fic) {…} ;
  • línea 18: fputs($fic,$chaîne) escribe la cadena en el archivo $fic. $chaine se escribe con el carácter de fin de línea \n al final;
  • línea 21: fclose($fic) cierra el archivo $fic;
  • línea 26: fopen(nom_fichier,"r") abre el archivo nom_fichier en modo lectura (r=read). Si la apertura falla (por ejemplo, porque el archivo no existe), fopen devuelve el valor false;
  • línea 34: fgets($fic,1000) lee la siguiente línea del archivo con un límite de 1000 caracteres. En la operación while ($ligne = fgets($fic, 1000)) {…}, hay dos operaciones sucesivas: 1) $ligne=fgets(…) 2) while ( ! $ligne). Una vez leído el último carácter del archivo, la función fgets devuelve el valor false y el bucle while se detiene. La función fgets intenta aquí leer un máximo de 1000 caracteres, pero se detiene en cuanto encuentra un carácter de fin de línea. Dado que todas las líneas tienen menos de 1000 caracteres, [fgets] lee una línea de texto, incluido el carácter de fin de línea. La función cutNewLineChar de las líneas 75-84 elimina los posibles caracteres de fin de línea;
  • línea 77: la función strlen($chaîne) devuelve el número de caracteres de $chaîne;
  • línea 78: la función substr($ligne, $position, $taille) devuelve $taille caracteres de $ligne, tomados a partir del carácter n.º $position, siendo el primer carácter el n.º 0. En equipos Windows, el marcador de fin de línea es «\r\n». En equipos Unix, es la cadena «\n»;
  • línea 40: la función array_shift($tableau) elimina el primer elemento de $tableau y lo devuelve como resultado. Aquí se omite el resultado devuelto por array_shift;
  • línea 62: la función is_array($variable) devuelve true si $variable es una matriz, false en caso contrario;
  • línea 63: la función join hace lo mismo que la función implode que ya hemos visto;

3.10. Codificación/decodificación jSON

Image

La codificación/decodificación jSON (JavaScript Object Notation) es algo que vamos a utilizar intensivamente en el ejercicio que sirve de hilo conductor del documento. Los scripts [json-01.php, json-02.php, json-03.php] explican lo que hay que saber para continuar.

El script [json-01.php] es el siguiente:


<?php

$array1 = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34];
// codificación json de la matriz array1 con caracteres Unicode escapados
print "encodage json du tableau array1 avec caractères Unicode échappés\n";
$json1 = json_encode($array1);
print "json1=$json1\n";
// codificación json de la matriz array1 con caracteres Unicode sin escapar
print "encodage json du tableau array1 avec caractères Unicode non échappés\n";
$json2 = json_encode($array1, JSON_UNESCAPED_UNICODE);
print "json2=$json2\n";
// decodificación jSON en matriz asociativa
print "décodage jSON de json2 dans tableau associatif\n";
$array2 = json_decode($json2, true);
var_dump($array2);
foreach ($array2 as $key => $value) {
  print "$key:$value\n";
}
// decodificación jSON en objeto
print "décodage jSON de json2 dans objet stdClass\n";
$array2 = json_decode($json2);
var_dump($array2);
print "prénom=$array2->prénom\n";
print "nom=$array2->nom\n";
print "âge=$array2->âge\n";

Resultados

encodage json du tableau array1 avec caractères Unicode échappés
json1={"nom":"s\u00e9l\u00e9n\u00e9","pr\u00e9nom":"b\u00e9n\u00e9dicte","\u00e2ge":34}
encodage json du tableau array1 avec caractères Unicode non échappés
json2={"nom":"séléné","prénom":"bénédicte","âge":34}
décodage jSON de json2 dans tableau associatif
array(3) {
  ["nom"]=>
  string(9) "séléné"
  ["prénom"]=>
  string(11) "bénédicte"
  ["âge"]=>
  int(34)
}
nom:séléné
prénom:bénédicte
âge:34
décodage jSON de json2 dans objet stdClass
object(stdClass)#1 (3) {
  ["nom"]=>
  string(9) "séléné"
  ["prénom"]=>
  string(11) "bénédicte"
  ["âge"]=>
  int(34)
}
prénom=bénédicte
nom=séléné
âge=34

Comentarios

  • línea 6 del código: la función [json_encode] transforma su parámetro en la cadena de caracteres jSON;
  • línea 2 de los resultados: la cadena jSON generada. Los caracteres Unicode éâ han sido sustituidos por su código Unicode, que comienza por \u;
  • línea 10 del código: se repite el mismo proceso, pero esta vez se indica que los caracteres Unicode se mantengan tal cual;
  • línea 4 de los resultados: la cadena resultante jSON. Es mucho más legible;
  • líneas 14-18 del código: se realiza la operación inversa. Se transforma una cadena jSON en una tabla asociativa;
  • líneas 6-13 de los resultados: vemos que hemos obtenido un array asociativo;
  • líneas 19-25 del código: se transforma una cadena jSON en un objeto de tipo [stdClass];
  • líneas 18-25 de los resultados: vemos que se ha recuperado un objeto de tipo [stdClass];
  • líneas 23-25 del código: el atributo A de un objeto O se denota como [O→A];

Se pueden codificar en jSON tablas de varios niveles, tal y como muestra el siguiente script [json-02.php]:


<?php

$array = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34,
  "mari" => ["nom" => "icariù", "prénom" => "ignacio", "âge" => 35],
  "enfants" => [
    ["prénom" => "angèle", "age" => 8],
    ["prénom" => "andré", "age" => 2],
  ]];
// codificación jSON de la matriz multinivel
print "encodage jSON d'un tableau à plusieurs niveaux\n";
$json = json_encode($array, JSON_UNESCAPED_UNICODE);
print "json=$json\n";

Resultados


encodage jSON d'un tableau à plusieurs niveaux
json={"nom":"séléné","prénom":"bénédicte","âge":34,"mari":{"nom":"icariù","prénom":"ignacio","âge":35},"enfants":[{"prénom":"angèle","age":8},{"prénom":"andré","age":2}]}

Comentarios

En la cadena jSON:

  • las matrices no asociativas están entre corchetes [];
  • las matrices asociativas se escriben entre llaves {};

El script [json-03.php] muestra cómo utilizar el siguiente archivo jSON [famille.json]:


{
    "épouse": {
        "nom": "séléné",
        "prénom": "bénédicte",
        "âge": 34
    },
    "mari": {
        "nom": "icariù",
        "prénom": "ignacio",
        "âge": 35
    },
    "enfants": [
        {
            "prénom": "angèle",
            "age": 8
        },
        {
            "prénom": "andré",
            "age": 2
        }
    ]
}

El script [json-03.php] es el siguiente:


<?php

// lectura del archivo jSON
$json = file_get_contents("famille.json");
// decodificación de json en objeto
$famille1 = json_decode($json);
print "----famille1\n";
var_dump($famille1);
// decodificación de json en tabla asociativa
print "----famille2\n";
$famille2 = json_decode($json, true);
var_dump($famille2);

Comentarios

  • línea 4: la función [file_get_contents] lee el contenido del archivo denominado [famille.json] y lo asigna a la variable [$json];
  • A continuación, la variable se decodifica en un objeto (líneas 5-8) y en una tabla asociativa (líneas 9-12);

Resultados


----familia1
object(stdClass)#2 (3) {
  ["épouse"]=>
  object(stdClass)#1 (3) {
    ["nom"]=>
    string(9) "séléné"
    ["prénom"]=>
    string(11) "bénédicte"
    ["âge"]=>
    int(34)
  }
  ["mari"]=>
  object(stdClass)#3 (3) {
    ["nom"]=>
    string(7) "icariù"
    ["prénom"]=>
    string(7) "ignacio"
    ["âge"]=>
    int(35)
  }
  ["enfants"]=>
  array(2) {
    [0]=>
    object(stdClass)#4 (2) {
      ["prénom"]=>
      string(7) "angèle"
      ["age"]=>
      int(8)
    }
    [1]=>
    object(stdClass)#5 (2) {
      ["prénom"]=>
      string(6) "andré"
      ["age"]=>
      int(2)
    }
  }
}
----familia2
array(3) {
  ["épouse"]=>
  array(3) {
    ["nom"]=>
    string(9) "séléné"
    ["prénom"]=>
    string(11) "bénédicte"
    ["âge"]=>
    int(34)
  }
  ["mari"]=>
  array(3) {
    ["nom"]=>
    string(7) "icariù"
    ["prénom"]=>
    string(7) "ignacio"
    ["âge"]=>
    int(35)
  }
  ["enfants"]=>
  array(2) {
    [0]=>
    array(2) {
      ["prénom"]=>
      string(7) "angèle"
      ["age"]=>
      int(8)
    }
    [1]=>
    array(2) {
      ["prénom"]=>
      string(6) "andré"
      ["age"]=>
      int(2)
    }
  }
}

Comentarios

  • líneas 1-38: el objeto resultante de la decodificación del archivo jSON [famille.json];
  • líneas 39-76: la matriz asociativa resultante de la decodificación del archivo jSON [famille.json];