tutorial instalar descargar php-7

instalar - Advertencias de silencio "Declaración... debería ser compatible" en PHP 7



php 7 tutorial (6)

1. Solución

Dado que no siempre es posible corregir todo el código que no escribió , especialmente el heredado ...

if (PHP_MAJOR_VERSION >= 7) { set_error_handler(function ($errno, $errstr) { return strpos($errstr, ''Declaration of'') === 0; }, E_WARNING); }

Este controlador de errores devuelve true para las advertencias que comienzan con la Declaration of que básicamente le dice a PHP que una advertencia fue atendida. Es por eso que PHP no informará esta advertencia en otro lugar.

Además, este código solo se ejecutará en PHP 7 o superior.

Si desea que esto suceda solo con respecto a una base de código específica, puede verificar si un archivo con un error pertenece a esa base de código o una biblioteca de interés:

if (PHP_MAJOR_VERSION >= 7) { set_error_handler(function ($errno, $errstr, $file) { return strpos($file, ''path/to/legacy/library'') !== false && strpos($errstr, ''Declaration of'') === 0; }, E_WARNING); }

2. Solución adecuada

En cuanto a corregir realmente el código heredado de otra persona, hay una serie de casos en los que esto podría hacerse entre fácil y manejable. En los ejemplos a continuación, la clase B es una subclase de A Tenga en cuenta que no necesariamente eliminará las infracciones de LSP siguiendo estos ejemplos.

  1. Algunos casos son bastante fáciles. Si en una subclase falta un argumento predeterminado, simplemente agréguelo y continúe. Por ejemplo, en este caso:

    Declaration of B::foo() should be compatible with A::foo($bar = null)

    Tu harías:

    - public function foo() + public function foo($bar = null)

  2. Si tiene restricciones adicionales agregadas en una subclase, elimínelas de la definición, mientras se mueve dentro del cuerpo de la función.

    Declaration of B::add(Baz $baz) should be compatible with A::add($n)

    Es posible que desee utilizar aserciones o lanzar una excepción según la gravedad.

    - public function add(Baz $baz) + public function add($baz) { + assert($baz instanceof Baz);

    Si ve que las restricciones se utilizan únicamente con fines de documentación, muévalas a donde pertenecen.

    - protected function setValue(Baz $baz) + /** + * @param Baz $baz + */ + protected function setValue($baz) { + /** @var $baz Baz */

  3. Si su subclase tiene menos argumentos que una superclase, y podría hacerlos opcionales en la superclase, simplemente agregue marcadores de posición en la subclase. Cadena de error dada:

    Declaration of B::foo($param = '''') should be compatible with A::foo($x = 40, $y = '''')

    Tu harías:

    - public function foo($param = '''') + public function foo($param = '''', $_ = null)

  4. Si ve algunos argumentos requeridos en una subclase, tome el asunto en sus manos.

    - protected function foo($bar) + protected function foo($bar = null) { + if (empty($bar[''key''])) { + throw new Exception("Invalid argument"); + }

  5. A veces puede ser más fácil alterar el método de la superclase para excluir un argumento opcional por completo, func_get_args magia func_get_args . No olvide documentar el argumento que falta.

    /** + * @param callable $bar */ - public function getFoo($bar = false) + public function getFoo() { + if (func_num_args() && $bar = func_get_arg(0)) { + // go on with $bar

    Claro que esto puede volverse muy tedioso si tiene que eliminar más de un argumento.

  6. Las cosas se vuelven mucho más interesantes si tiene violaciones graves del principio de sustitución. Si no tiene argumentos escritos, entonces es fácil. Simplemente haga que todos los argumentos adicionales sean opcionales, luego verifique su presencia. Error dado:

    Declaration of B::save($key, $value) should be compatible with A::save($foo = NULL)

    Tu harías:

    - public function save($key, $value) + public function save($key = null, $value = null) { + if (func_num_args() < 2) { + throw new Exception("Required argument missing"); + }

    Tenga en cuenta que no podríamos usar func_get_args() aquí porque no tiene en cuenta los argumentos predeterminados (no aprobados). Solo nos queda func_num_args() .

  7. Si tiene una jerarquía completa de clases con una interfaz divergente, puede ser más fácil divergirla aún más. Cambie el nombre de una función con una definición conflictiva en cada clase. Luego agregue una función proxy en un solo padre intermediario para estas clases:

    function save($arg = null) // conforms to the parent { $args = func_get_args(); return $this->saveExtra(...$args); // diverged interface }

    De esta forma, se seguiría violando el LSP, aunque sin previo aviso, pero puede mantener todos los controles de tipo que tenga en las subclases.

Después de la actualización a PHP 7, los registros casi se ahogaron con este tipo de errores:

PHP Warning: Declaration of Example::do($a, $b, $c) should be compatible with ParentOfExample::do($c = null) in Example.php on line 22548

¿Cómo puedo silenciar estos y solo estos errores en PHP 7?

  • Antes de PHP 7, eran E_STRICT tipo E_STRICT que podían tratarse fácilmente . Ahora son simples advertencias antiguas. Como quiero saber sobre otras advertencias, no puedo desactivar todas las advertencias por completo.

  • No tengo la capacidad mental para reescribir estas API heredadas sin mencionar siquiera todo el software que las usa. Adivina qué, nadie va a pagar por eso también. Tampoco los desarrollo en primer lugar, así que no soy el culpable. (¿Pruebas unitarias? No en la moda hace diez años).

  • Me gustaría evitar cualquier truco con func_get_args y similares tanto como sea posible.

  • Realmente no quiero degradar a PHP 5.

  • Todavía quiero saber sobre otros errores y advertencias.

¿Hay una manera limpia y agradable de lograr esto?


Estoy de acuerdo: el ejemplo en la primera publicación es una mala práctica. Ahora, ¿qué pasa si tienes ese ejemplo?

class AnimalData { public $shout; } class BirdData extends AnimalData { public $wingNumber; } class DogData extends AnimalData { public $legNumber; } class AnimalManager { public static function displayProperties(AnimalData $animal) { var_dump($animal->shout); } } class BirdManager extends AnimalManager { public static function displayProperties(BirdData $bird) { self::displayProperties($bird); var_dump($bird->wingNumber); } } class DogManager extends AnimalManager { public static function displayProperties(DogData $dog) { self::displayProperties($dog); var_dump($dog->legNumber); } }

Creo que esta es una estructura de código legítima, sin embargo, esto generará una advertencia en mis registros porque displayProperties() no tiene los mismos parámetros. Además, no puedo hacerlos opcionales agregando a = null después de ellos ...

¿Estoy en lo cierto pensando que esta advertencia es incorrecta en este ejemplo específico por favor?


PHP 7 elimina el nivel de error E_STRICT . Puede encontrar información sobre esto en las notas de compatibilidad de PHP7 . También es posible que desee leer el documento de propuesta donde se discutió mientras se desarrollaba PHP 7.

El hecho simple es este: los avisos E_STRICT se introdujeron hace varias versiones, en un intento de notificar a los desarrolladores que estaban usando malas prácticas, pero inicialmente sin intentar forzar ningún cambio. Sin embargo, las versiones recientes, y PHP 7 en particular, se han vuelto más estrictas sobre estas cosas.

El error que está experimentando es un caso clásico:

Ha definido un método en su clase que anula un método del mismo nombre en la clase principal, pero su método de anulación tiene una firma de argumento diferente.

La mayoría de los lenguajes de programación modernos no permitirían esto en absoluto. PHP solía permitir que los desarrolladores se salieran con la suya, pero el lenguaje se está volviendo más estricto con cada versión, especialmente ahora con PHP 7: eligieron un nuevo número de versión principal específicamente para que puedan justificar hacer cambios significativos que rompen compatibilidad con versiones anteriores.

El problema que tiene es porque ya ha estado ignorando los mensajes de advertencia. Su pregunta implica que esta es la solución con la que desea continuar, pero los mensajes como "estricto" y "obsoleto" deben tratarse como una advertencia explícita de que es probable que su código se rompa en futuras versiones. Al ignorarlos durante los últimos años, te has colocado efectivamente en la situación que tienes ahora. (Sé que eso no es lo que quieres escuchar, y realmente no ayuda a la situación ahora, pero es importante dejarlo claro)

Realmente no hay una solución alternativa del tipo que estás buscando. El lenguaje PHP está evolucionando, y si desea seguir con PHP 7, su código también deberá evolucionar. Si realmente no puede arreglar el código, tendrá que suprimir todas las advertencias o vivir con estas advertencias abarrotando sus registros.

La otra cosa que necesita saber si planea seguir con PHP 7 es que hay una serie de otras interrupciones de compatibilidad con esta versión, incluidas algunas que son bastante sutiles. Si su código está en un estado en el que tiene errores como el que está informando, significa que probablemente haya existido durante bastante tiempo, y que probablemente tenga otros problemas que le causarán problemas en PHP 7. Para un código como este, Sugeriría hacer una auditoría más exhaustiva del código antes de comprometerse con PHP 7. Si no está preparado para hacerlo, o no está preparado para corregir los errores encontrados (y la implicación de su pregunta es que no lo está) , entonces sugeriría que PHP 7 es probablemente una actualización demasiado lejos para usted.

Tienes la opción de volver a PHP 5.6. Sé que dijiste que no quieres hacer eso, pero como una solución a corto y mediano plazo, te facilitará las cosas. Francamente, creo que podría ser tu mejor opción.


Para aquellos que desean corregir su código para que ya no active la advertencia: me pareció útil saber que puede agregar parámetros adicionales a los métodos anulados en las subclases siempre que les dé valores predeterminados. Entonces, por ejemplo, mientras esto activará la advertencia:

//"Warning: Declaration of B::foo($arg1) should be compatible with A::foo()" class B extends A { function foo($arg1) {} } class A { function foo() {} }

Esto no:

class B extends A { function foo($arg1 = null) {} } class A { function foo() {} }


Si debe silenciar el error, puede declarar la clase dentro de una expresión de función silenciada e invocada de inmediato:

<?php // unsilenced class Fooable { public function foo($a, $b, $c) {} } // silenced @(function () { class ExtendedFooable extends Fooable { public function foo($d) {} } })();

Sin embargo, recomendaría enfáticamente esto. Es mejor arreglar su código que silenciar las advertencias sobre cómo se rompe.

Si necesita mantener la compatibilidad con PHP 5, tenga en cuenta que el código anterior solo funciona en PHP 7, porque PHP 5 no tenía una sintaxis uniforme para las expresiones . Para que funcione con PHP 5, deberá asignar la función a una variable antes de invocarla (o convertirla en una función con nombre):

$_ = function () { class ExtendedFooable extends Fooable { public function foo($d) {} } }; @$_(); unset($_);


También tuve este problema. Tengo una clase que anula una función de la clase principal, pero la anulación tiene un número diferente de parámetros. Puedo pensar en algunas soluciones sencillas, pero requieren un cambio menor de código.

  1. cambiar el nombre de la función en la subclase (para que ya no anule la función principal) -o--
  2. cambiar los parámetros de la función principal, pero hacer que los parámetros adicionales sean opcionales (por ejemplo, función func ($ var1, $ var2 = null); esto puede ser más fácil y requerir menos cambios de código. Pero puede no valer la pena cambiar esto en el padre si ha usado muchos otros lugares, así que fui con el # 1 en mi caso.

  3. Si es posible, en lugar de pasar los parámetros adicionales en la función de subclase, use global para extraer los parámetros adicionales. Esta no es la codificación ideal; pero una posible tirita de todos modos.