Supoñamos que no noso programa hai unha función definida e que o código avaliado contén unha que se chame igual. Qué sucedería? Cómo resolverlo?
Se temos nun ficheiro definida unha función co nome "foo()", ao executar o codigo, sen ter en conta ningunha modificación, a mensaxe de erro que obtemos será similar a seguinte:
Fatal error: Cannot redeclare foo() (previously declared in....
Para facer unha proba creamos un ficheiro como o seguinte:
<?php
error_reporting(E_ALL);
################################################################################
function foo() {
echo "Funcion foo orixinal" . PHP_EOL;
}
// Invocamos foo()
foo();
################################################################################
$code =<<< PHPCODE
function foo() {
echo "Funcion foo dende eval" . PHP_EOL;
}
PHPCODE;
// Tentamos avaliar $code
eval($code); // Fatal error: Cannot redeclare foo() (previously declared in...
Ao estar definida unha función co mesmo nome, en tempo de execución, ao procesar o código da sentencia exec lanza un erro. Un método sinxelo sería comprobar se a función xa está definida con function_exists. Outra posibilidade sería empregar extensións do motor Zend de PHP que permitan a "redefinición" da función (runkit, APD). No seguinte código recóllese un exemplo de uso de runkit para redefinir a función, con runkit_function_redefine:
$code =<<< PHPCODE
if(function_exists('foo')){
// Redefinir a función
runkit_function_redefine('foo', '', 'echo "(runkit version)" . PHP_EOL;');
} else {
function foo() {
echo "Funcion foo dende eval (sen redefinir)" . PHP_EOL;
}
}
PHPCODE;
eval($code) . PHP_EOL;
foo();
Instalación de runkit
Compilación e instalación da extensión runkit en contornos debian/ubuntu.
- Comprobar que está instalado o paquete php5-dev (en distribucións debian).
- Descargar os fontes de runkit do repositorio pecl de PHP:
:~/$ wget http://pecl.php.net/get/runkit-0.9.tgz
- Descomprimir os fontes de runkit:
:~/$ tar xzvf runkit-0.9.tgz
:~/$ cd runkit-0.9
- Compilar a extensión PHP (NON executar o comando make install):
:~/$ phpize :~/$ ./configure :~/$ make
- Se aparece algunha mensaxe de erro ao executar o comando make é posible que sexa por culpa dun bug nas versións de PHP 5.2.x . Para correxir este bug hai que facer uns cambios no ficheiro fonte runkit_import.c
// Cambiar esta liña
zend_unmangle_property_name(key, &cname, &pname);
// por esta outra
zend_unmangle_property_name(key, key_len, &cname, &pname);
- Instalar a extensión copiando runkit.so ao directorio de extensións de PHP, indicarlle a PHP que cargue a extensión e reiniciar apache.
// Averiguar a ruta ao directorio de extensións de PHP
:~# php -r "phpinfo();" | grep extension_dir
extension_dir => /usr/lib/php5/20060613+lfs => /usr/lib/php5/20060613+lfs
:~# sudo cp .libs/runkit.so /usr/lib/php5/20060613+lfs/
:~# echo "extension=runkit.so" > /etc/php5/conf.d/runkit.ini
:~# apache2ctl restart
- Unha vez reiniciado o servidor Apache2 xa teremos a nosa disposición a extensión runkit.
Redefinición de funcións en PHP 5.3
O uso de namespaces na versión 5.3 de PHP permite a definición dunha función nun espazo de nomes distinto non provocará colisións coa definida noutro.
namespace CDWA\PHP {
$foo = function() {echo "Funcion en namespace CDWA\\PHP" . PHP_EOL;};
$foo(); // A do namespace
\foo(); // A orixinal
}





