2009-09-11 76 views
10

有一个项目,我需要扩展。所有类都在单独的文件中,我需要扩展一些类而不重写其他文件中的现有代码。我的想法是使用命名空间,但我失败了。这里有一个例子:PHP命名空间和包含()与类

我已经改名为原来 a.php只会类文件 A_Original.php

class A 
{ 

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

} 

然后创建一个新的 a.php只会

namespace AOriginal { 

    include 'A_Original.php'; 
} 


namespace { 

class A 
{ 

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

} 

} 

由于including原始的A_Original.php文件,该类被转储到全局作用域(因此忽略命名空间命令),因此失败。 我无法修改A_Original.php文件中的现有代码,但重命名是可以的。

其他项目文件(我无法修改)使用require "A.php"

如何做到这一点?

回答

-4

eval()怎么样?

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

不起作用,如果a_original.php类基于另一个类 class A extends SomeOtherClass,因为现在这个其他类应该在同一个命名空间 - 这不是包括(“someotherclass.php”) - 它在全球范围内。 aaargs。我迷路了。包含()不应该改变当前的命名空间 - 但它确实! – cydo 2009-09-15 12:38:31

3

可以扩展一个类,而无需修改其现有的行为:

class A { 
    public function foo(){ 

    } 
} 

class MySubClassOfA extends A { 
    public function bar(){ 

    } 
} 

您可以添加自己的方法来MySubClassOfA,即巴()。你可以在MySubClassOfA上调用foo方法,它的行为是一样的,除非你在MySubClassOfA中定义了一个叫做foo的方法。

+1

如果我没有弄错cydo想要类似Ruby的'extend'或'include'。实例化A类对象的Existing_代码获取更改/增强版本,而不更改该代码库。 – VolkerK 2009-09-11 10:16:25

+0

啊 - 这听起来很危险 – 2009-09-11 10:19:21

+1

VolkerK:对。这就是我需要的。 – cydo 2009-09-11 11:25:21

1

我猜你别无选择,只能添加“namespace xxx;”一行代码上的所有文件的顶部。以下PHP CLI脚本可能会有用。

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