2009-09-11 17 views
10

c'è un progetto che ho bisogno di estendere. Tutte le classi sono in file separati, ho bisogno di estendere alcune delle classi senza riscrivere il codice esistente in altri file. La mia idea era di usare gli spazi dei nomi ma non ci riesco. Ecco un esempio:Namespace PHP e Include() con classi

ho rinominato il file classe originale A.php a A_Original.php:

class A 
{ 

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

} 

poi creato un nuovo A.php:

namespace AOriginal { 

    include 'A_Original.php'; 
} 


namespace { 

class A 
{ 

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

} 

} 

Ciò non riesce perché su including il file A_Original.php originale la classe viene scaricata sull'ambito globale (ignorando quindi il comando namespace). Non riesco a modificare il codice esistente nel file A_Original.php, ma la ridenominazione è ok.

Gli altri file di progetto (che non è possibile modificare) utilizzano uno require "A.php".

Come realizzare questo?

risposta

-4

Che ne dici di eval()?

Nuova 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

non funziona se la classe a_original.php è basata su un'altra classe class A extends SomeOtherClass perché ora questa altra classe dovrebbe essere nello stesso spazio dei nomi, che non è incluso ("someotherclass.php") - è nell'ambito globale. aaargs. Mi sono perso. include() non dovrebbe cambiare lo spazio dei nomi corrente - ma lo fa! – cydo

3

È possibile estendere una classe senza modificarne il comportamento esistente:

class A { 
    public function foo(){ 

    } 
} 

class MySubClassOfA extends A { 
    public function bar(){ 

    } 
} 

È possibile aggiungere i propri metodi per MySubClassOfA, vale a dire bar(). È possibile chiamare il metodo foo su MySubClassOfA e il suo comportamento è lo stesso, a meno che non si definisca un metodo chiamato foo in MySubClassOfA.

+1

Se non sbaglio, cydo vuole qualcosa come "estendi" o "include" di Ruby. _ Il codice_esistente che crea un'istanza dell'oggetto di classe A ottiene la versione modificata/potenziata senza modificare quella base di codice. – VolkerK

+0

Ah: sembra pericoloso –

+1

VolkerK: giusto. quello è ciò di cui ho bisogno. – cydo

1

Immagino che non hai scelta, ma aggiunge la singola riga di codice "namespace xxx;" in cima a tutti i vostri file. Il seguente script CLI PHP può essere utile.

<?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]); 
    } 
} 
?>