PHP命名空间和包含类的Include()

时间:2009-09-11 09:37:13

标签: php namespaces

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

我已将原来的 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";
    }

}

}

这会失败,因为在原始A_Original.php文件的including上,类被转储到全局范围(因此忽略命名空间命令)。 我无法修改A_Original.php文件中的现有代码,但重命名是可以的。

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

如何做到这一点?

3 个答案:

答案 0 :(得分:3)

您可以在不修改现有行为的情况下扩展类:

class A {
  public function foo(){

  }
}

class MySubClassOfA extends A {
  public function bar(){

  }
}

您可以将自己的方法添加到MySubClassOfA,即bar()。您可以在MySubClassOfA上调用foo方法,它的行为是相同的,除非您在MySubClassOfA中定义了一个名为foo的方法。

答案 1 :(得分: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]);
  }
}
?>

答案 2 :(得分:-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";
    }
}