【问题标题】:PHP Namespace and Include() with classesPHP 命名空间和 Include() 与类
【发布时间】:2010-11-27 10:54:51
【问题描述】:

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

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

如何做到这一点?

【问题讨论】:

    标签: php namespaces


    【解决方案1】:

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

    class A {
      public function foo(){
    
      }
    }
    
    class MySubClassOfA extends A {
      public function bar(){
    
      }
    }
    

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

    【讨论】:

    • 如果我没记错的话,cydo 想要像 Ruby 的 extendinclude 这样的东西。实例化 A 类对象的现有代码在不更改该代码库的情况下获取更改/增强版本。
    【解决方案2】:

    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";
        }
    }
    

    【讨论】:

    • 如果 a_original.php 类基于另一个类 class A extends SomeOtherClass 则不起作用,因为现在这个其他类应该在同一个命名空间中 - 不包括("someotherclass.php") - 它在全局范围内。啊啊啊我迷路了。 include() 不应该改变当前的命名空间 - 但它会!
    【解决方案3】:

    我猜你别无选择,只能在所有文件的顶部添加一行“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]);
      }
    }
    ?>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-04
      • 2014-06-07
      • 2012-08-10
      • 2014-08-12
      • 2012-10-14
      • 1970-01-01
      • 1970-01-01
      • 2016-03-25
      相关资源
      最近更新 更多