2009-09-11 22 views
10

hay un proyecto que necesito extender. Todas las clases están en archivos separados, necesito extender algunas de las clases sin reescribir el código existente en otros archivos. Mi idea era usar espacios de nombres pero fallo. Aquí está un ejemplo:PHP Namespace e Include() con las clases

He cambió el nombre del archivo original clase A.php a A_Original.php:

class A 
{ 

    public function hello() 
    { 
     echo "hello world from Class A\n"; 
    } 

} 

creó entonces un nuevo A.php:

namespace AOriginal { 

    include 'A_Original.php'; 
} 


namespace { 

class A 
{ 

    public function hello() 
    { 
     echo "hello world from Class A Extended\n"; 
    } 

} 

} 

Esto falla porque en including el archivo A_Original.php original la clase se descarga al ámbito global (ignorando así el comando de espacio de nombres). No puedo modificar el código existente en el archivo A_Original.php, pero el cambio de nombre está bien.

Los otros archivos de proyecto (que no puedo modificar) usan un require "A.php".

¿Cómo lograr esto?

Respuesta

-4

¿Qué tal eval()?

Nueva A.php

$lines = file('a_original.php'); 
array_unshift($lines, 'namespace AO;?>'); 
$string = implode(chr(13).chr(10), $lines); 
eval($string); 

class A extends AO\A 
{ 
    public function hello() 
    { 
     parent::hello(); 
     echo "hello world from Class A Extended\n"; 
    } 
} 
+1

no funciona si la clase a_original.php se basa en otra clase class A extends SomeOtherClass porque ahora esta otra clase debe estar en el mismo espacio de nombres, que no está incluido ("someotherclass.php"), está en el ámbito global. aaargs. Estoy perdido. include() no debería cambiar el espacio de nombres actual, ¡pero sí! – cydo

3

Se puede extender una clase sin modificar su comportamiento existente:

class A { 
    public function foo(){ 

    } 
} 

class MySubClassOfA extends A { 
    public function bar(){ 

    } 
} 

Usted puede añadir sus propios métodos para MySubClassOfA, es decir, la barra(). Puede llamar al método foo en MySubClassOfA y su comportamiento es el mismo, a menos que defina un método llamado foo en MySubClassOfA.

+1

Si no me equivoco, cydo quiere algo como Ruby's 'extend' o' include'. _El código existente que crea una instancia de un objeto de clase A obtiene la versión modificada/modificada sin cambiar esa base de código. – VolkerK

+0

Ah - esto suena peligroso –

+1

VolkerK: a la derecha. eso es lo que necesito. – cydo

1

supongo que usted no tiene más remedio que añadir la línea de código "namespace xxx;" en la parte superior de todos sus archivos. La siguiente secuencia de comandos PHP CLI puede ser útil.

<?php 
function convert($namespace, $srcdir, $dstdir) 
{ 
    try 
    { 
    $files = glob("$srcdir/{*,.*}", GLOB_BRACE); 

    if (! file_exists($dstdir) && ! mkdir($dstdir)) 
    { 
     throw new Exception("Cannot create directory {$dstdir}"); 
    } 

    if (! is_dir($dstdir)) 
    { 
     throw new Exception("{$dstdir} is not a directory"); 
    } 

    foreach ($files as $f) 
    { 
     extract(pathinfo($f)); // then we got $dirname, $basename, $filename, $extension 

     if ($basename == '.' || $basename == '..') 
     { 
     continue; 
     } 

     if (is_dir($f)) 
     { 
     $d = $dstdir. substr($f, strlen($srcdir)); 
     convert($namespace, $f, $d); 
     continue; 
     } 

     print "processing {$f} ... "; 

     if (($s = file_get_contents($f)) === FALSE) 
     { 
     throw new Exception("Error reading $f"); 
     } 

     if (preg_match("/^\s*namespace\s+\S+;/m", $s)) 
     { 
     print "already has namespace, skip"; 
     } 
     else 
     { 
     $lines = preg_split("/(\n|\r\n)/", $s); 
     $output = array(); 
     $matched = FALSE; 

     foreach ($lines as $s) 
     { 
      $output[] = $s; 

      // check if this is a PHP code? 
      if (! $matched && preg_match('/<(\?(php)*|%)/', $s)) 
      { 
      $matched = TRUE; 
      print "insert namespace ... "; 
      $output[] = "namespace {$namespace};"; 
      } 
     } 

     if (file_put_contents("{$dstdir}/{$basename}" , implode("\n", $output)) === FALSE) 
     { 
      throw new Exception("Cannot save file {$dstdir}/{$basename}"); 
     } 

     if (! $matched) 
     { 
      print ("not a PHP file, skip."); 
     } 
     else 
     { 
      print "done!"; 
     } 
     } 

     print "\n"; 
    } 
    } 
    catch (Exception $e) 
    { 
    print 'Error: '. $e->getMessage() .' ('. $e->getCode() .')' ."\n"; 
    } 
} 

extract($_SERVER); 

if ($argc < 4) 
{ 
?> 
Usage: php -F <?=$argv[0]?> <namespace> <source_dir(s)> <dst_dir> 
Convert PHP code to be namespace-aware 
<? 
    return; 
} 
else 
{ 
    for ($i = 2; $i < $argc - 1; $i++) 
    { 
    convert($argv[1], $argv[$i], $argv[$argc-1]); 
    } 
} 
?>