2009-09-11 8 views
10

gibt es ein Projekt, das ich erweitern muss. Alle Klassen sind in separaten Dateien, ich muss einige der Klassen erweitern, ohne bestehenden Code in andere Dateien umzuschreiben. Meine Idee war, Namensräume zu verwenden, aber ich scheitere. Hier ein Beispiel:PHP-Namespace und Include() mit Klassen

ich die ursprüngliche A.php Klassendatei A_Original.php umbenannt habe:

class A 
{ 

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

} 

dann ein neues A.php erstellt:

namespace AOriginal { 

    include 'A_Original.php'; 
} 


namespace { 

class A 
{ 

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

} 

} 

Dies schlägt fehl, weil auf including die ursprüngliche A_Original.php-Datei die Klasse in den globalen Bereich ausgegeben wird (ignoriert also den Namespace-Befehl). Ich kann den vorhandenen Code in der Datei A_Original.php nicht ändern, aber das Umbenennen ist in Ordnung.

Die anderen Projektdateien (die ich nicht ändern kann) verwenden eine require "A.php".

Wie wird das erreicht?

Antwort

-4

Wie wäre es mit eval()?

New 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

funktioniert nicht, wenn die Klasse a_original.php auf einer anderen Klasse basiert class A extends SomeOtherClass, weil jetzt diese andere Klasse im selben Namespace sein sollte - was nicht im including ("someotherclass.php") - es im globalen Bereich ist. aaargs. Ich bin verloren. include() sollte nicht den aktuellen Namespace ändern - aber es tut! – cydo

3

Sie können eine Klasse erweitern, ohne das bestehende Verhalten zu ändern:

class A { 
    public function foo(){ 

    } 
} 

class MySubClassOfA extends A { 
    public function bar(){ 

    } 
} 

Sie können Ihre eigenen Methoden zu MySubClassOfA hinzufügen, das heißt bar(). Sie können die foo-Methode auf MySubClassOfA aufrufen, und das Verhalten ist dasselbe, es sei denn, Sie definieren eine Methode namens foo in MySubClassOfA.

+1

Wenn ich mich nicht irre, möchte cydo etwas wie Ruby 'extend' oder' include' haben. Existierender Code, der ein Objekt der Klasse A instanziiert, erhält die geänderte/erweiterte Version, ohne diese Codebasis zu ändern. – VolkerK

+0

Ah - das klingt gefährlich –

+1

Volkerk: richtig. das ist was ich brauche. – cydo

1

Ich denke, dass Sie keine andere Wahl haben, als die einzige Zeile „namespace xxx;“ Code oben auf alle Ihre Dateien hinzuzufügen. Das folgende PHP CLI-Skript kann nützlich sein.

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