¿Qué es lo nuevo en PHP 7.1?

Como comentaba en ¿Qué es lo nuevo en PHP-7.0? PHP va en la dirección de convertirse un lenguaje de programacíon mixto: con características de un lenguaje dinámico y características de un lenguaje tipeado y muestra de ellos es que con la salida de la versión 7.1 de las 12 nuevas características 2 son de un lenguage tipeado: Tipos “nullable” y funciones void, otras de las carecterísticas incluidas en esta versión son:

  • desampaque simétrico de arreglos
  • visibilidad de las constantes de clase
  • seudotipo iterable
  • manipulación de múltiples excepciones en un solo catch
  • soporte para claves en list()

Las cuales comentamos a continuación.

1. Tipos “nullable”

Ahora las funciones pueden devolver nulo prefijando el tipo de datos con un signo de interrogación (?), de manera similar los párametros pueden aceptar nulo prefijando el tipo de datos con un signo de interrogación.

En caso de devolver un tipo de dato diferente al especifícado en el retorno de una función o se pasa un tipo de dato diferente especifícado en la definición de parámetros se emitira un error de tipo: TypeError

Ejemplos

1. Retorno de tipo string o null

<?php
function returnStringOrNull($valueToReturn): ?string {
    return $valueToReturn;
}

echo 'LibreByte:', gettype(returnStringOrNull('LibreByte')), nl2br("\n");
echo 'null:', gettype(returnStringOrNull(null)), nl2br("\n");
echo '25:', gettype(returnStringOrNull(25)), nl2br("\n");
echo 'SdtClass object:', gettype(returnStringOrNull(new StdClass())), nl2br("\n");

// Imprime/Print
// LibreByte:string
// null:NULL
// 25:string
// SdtClass object:
// Fatal error: Uncaught TypeError: Return value of returnStringOrNull() must be of the type string or null, object returned...

2. Parametro de tipo string o null

<?php
function stringOrNullParam(?string $param) {
    echo 'Param: ', is_null($param) ? "'null'" : "'$param'", ", type: ", gettype($param), nl2br("\n");
}

stringOrNullParam('LibreByte');
stringOrNullParam(null);
stringOrNullParam(25);
stringOrNullParam(new StdClass());

// Imprime/Print
// Param: 'LibreByte', type: string
// Param: 'null', type: NULL
// Param: '25', type: string
// Fatal error: Uncaught TypeError: Argument 1 passed to stringOrNullParam() must be of the type string or null, object given...

Nótese en ambos casos como PHP convierte el entero (25) a cadena, si quiere cambiar este comportamiendo use la siguiente sentencia declare(strict_types = 1)

2. Funciones void

Las funciones de tipos void no deben devolver ningún valor por tanto deben usar un return vacío o omitirlo completamente, pienso que si se omite el return le da más claridad al código ya que está más acorde con la definición de void, el valor NULL no es un valor válido de retorno para las funciones tipo void.

<?php
$a = 10;

function voidWithoutReturn(&$param, $newValue): void {
    $param = $newValue;
}

function voidWithEmptyReturn(&$param, $newValue): void {
    $param = $newValue;
    return;
}

echo 'Initial value for a: ', $a, nl2br("\n");
voidWithoutReturn($a, 25);
echo 'Called voidWithoutReturn($a, 25), $a = ', $a, nl2br("\n");
voidWithEmptyReturn($a, 30);
echo 'Called voidWithEmptyReturn($a, 30), a = ', $a, nl2br("\n");

// Imprime/Print
// Initial value for a: 10
// Called voidWithoutReturn($a, 25), $a = 25
// Called voidWithEmptyReturn($a, 30), a = 30

Si trata de devolver un valor dentro de una función void PHP emitirá un error como el siguiente

Fatal error: A void function must not return a value...

3. Desempaque simétrico de arreglos

A partir de la versión 5.4 PHP introdujo una sintaxis corta para declarar arreglos: $arr = [1, 2, 3]; esto nos permite sustituir la palabra clave: array por [].

Ahora se puede desempacar un arreglo usando corchetes: [] (tienen la misma funcionalidad que la sentencia list, también se pueden usar dentro de un foreach). Está característica es muy útil para el trabajo con arreglos multidimensionales y matrices.

<?php
$playerRank = [
    ['Carlsen',    'Norway',     2842],
    ['Caruana',    'USA',        2822],
    ['Mamedyarov', 'Azerbaijan', 2801],
    ['Ding Liren', 'China',      2797],
    ['Kramnik',    'Russia',     2790],
];

[$player1, $player2] = $playerRank;

echo "<strong>Player 1 is:</strong>", nl2br("\n");

foreach ($player1 as $data) {
    echo $data, nl2br("\n");
}
// Print
// Player 1 is:
// Carlsen
// Norway
// 2842

echo  nl2br("\n");
echo "<strong>Player 2 is:</strong>", nl2br("\n");

foreach ($player2 as $data) {
    echo $data, nl2br("\n");
}
// Print
// Player 2 is:
// Caruana
// USA
// 2822
echo  nl2br("\n");
echo "<strong>Player List:</strong>", nl2br("\n");

foreach ($playerRank as [$name, $country, $elo]) {
    echo "<strong>Player Name:</strong> $name, ", "<strong>Player Country: </strong> $country,",  "<strong>Elo: </strong> $elo";
    echo  nl2br("\n");
}
// Print
// Player List:
// Player Name: Carlsen, Player Country: Norway,Elo: 2842
// Player Name: Caruana, Player Country: USA,Elo: 2822
// Player Name: Mamedyarov, Player Country: Azerbaijan,Elo: 2801
// Player Name: Ding Liren, Player Country: China,Elo: 2797
// Player Name: Kramnik, Player Country: Russia,Elo: 2790

También es posible usar llaves o índices

<?php
echo "<strong>Countries:</strong>", nl2br("\n");

$countries = [
    'SPAIN'   => ['EUR', 'ES'],
    'USA'     => ['USD', 'EN'],
    'ECUADOR' => ['USD', 'ES'],
    'CUBA'    => ['CUC', 'ES'],
    'FRANCE'  => ['EUR', 'FR']
];

foreach ($countries as $countryName => [$currency, $lang]) {
    echo "<strong>Country: </strong> $countryName, <strong>Currency: </strong> $currency, <strong>Language: </strong> $lang";
    echo  nl2br("\n");
}
// Print
// Countries:
// Country: SPAIN, Currency: EUR, Language: ES
// Country: USA, Currency: USD, Language: EN
// Country: ECUADOR, Currency: USD, Language: ES
// Country: CUBA, Currency: CUC, Language: ES
// Country: FRANCE, Currency: EUR, Language: FR

4. Visibilidad de las constantes de clase

Esta característica mejora el encapsulamiento en la Programación Orientada a Objetos ya que, ahora, a las constantes de clase se le puede definir la visibilidad o alcance:

  • pública (valor por defecto, visible desde cualquier parte de su aplicación),
  • protejida (visible en la clase donde se declara y subclases) o
  • privada (solo visible en la clase donde se declara).
<?php
class Blog
{
    const BLOG_NAME = 'LibreByte';
    protected const START_DATE = '01-01-2007';
    private const CREATOR = 'srd0tlibr3';
}

class Page extends Blog
{
    public static function printDetails()
    {
        echo "Blog name: ", self::BLOG_NAME, nl2br("\n");
        echo "Blog start date: ", self::START_DATE, nl2br("\n");
        echo "Blog creator: ", self::CREATOR, nl2br("\n");
    }
}

Page::printDetails();

// Print
// Blog name: LibreByte
// Blog start date: 01-01-2007
// Blog creator: 
// Fatal error: Uncaught Error: Undefined class constant 'CREATOR'

Nótese que la constante CREATOR no es visible desde la clase Page.

5. Seudotipo iterable

Se ha introducido un nuevo seudotipo (similar a callable) llamado iterable. Se puede utilizar en parámetros y tipos de retorno, donde acepta tanto arrays u objetos que implementen la interfaz Traversable.

<?php
function xrange($start, $limit, $step = 1) {
    for ($i = $start; $i <= $limit; $i += $step) {
        yield $i;
    }
}

function iterate(iterable $iter)
{
    foreach ($iter as $val) {
        echo $val, ' ';
    }
}
// Print: 1 2 3 4 5 6 7 8 9 10
iterate(xrange(1, 10));

En el ejemplo anterior le pasamos a la funcion iterate un generator esto es posible debido a que la clase Generator implementa la interfaz Iterator que a su vez extiende la interfaz Traversable.

6. Manipulación de múltiples excepciones en un solo catch

PHP 7.1 permite capturar varias excepciones en un solo catch separando cada exception con una barra vertical: |.

<?php
function validateAge($age)
{
    if (!is_int($age)) {
        throw new InvalidArgumentException('Age must be integer!');
    }

    if (($age < 0) || ($age > 200)) {
        throw new DomainException('Age must be a value between 0 and 200!');
    }

    return true;
}

foreach ([3.5, 250] as $age) {
    try {
        if (validateAge($age)) {
            echo 'Valid age!', nl2br("\n");
        }
    } catch (InvalidArgumentException|DomainException $e) {
        echo $e->getMessage(), nl2br("\n");
    }
}

// Imprime/Print
// Age must be integer!
// Age must be a value between 0 and 200!

7. Soporte para claves en list()

Ahora se pueden especificar claves en list(), o en su nueva sintaxis abreviada []. Esto habilita el desempaque de arreglos con claves no enteras o no secuenciales.

<?php
$countries = [
    ['country' => 'Spain', 'lang' => 'ES', 'currency' => 'EUR'],
    ['country' => 'USA', 'lang' => 'EN', 'currency' => 'USD']
];

foreach ($countries as ['country' => $countryName, 'lang' => $language, 'currency' => $currency]) {
    echo "<strong>Country: </strong> $countryName, <strong>Language: </strong> $language, <strong>Currency: </strong> $currency";
    echo  nl2br("\n");
}

// Imprime/Print
// Country: Spain, Language: ES, Currency: EUR
// Country: USA, Language: EN, Currency: USD

8. Soporte para índices negativos de cadenas

Ahora las funciones de cadenas soportan índices aceptan índices negativos, un índice negativo se interpreta como un índice desde el final de la cadena. Versiones menor a la 7.1 ignoran los índices negativos sin emitir un mensaje de error.

<?php
var_dump("abcdef"[-2]); // Print: string (1) "e"
var_dump(strpos("aabbcc", "b", -3)); // Print: int(3)
$string = 'bar';
echo "The last character of '$string' is '$string[-1]'.\n"; // Print: The last character of 'bar' is 'r'. 

Lectura recomendada

YouTube video

PHP nuevas características, 2 (8)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.