Пространство имен PHP и Include() с классами

есть проект, который мне нужно расширить. Все классы находятся в отдельных файлах, мне нужно расширить некоторые классы без перезаписи существующего кода в других файлах. Моя идея заключалась в использовании пространств имен, но я терпел неудачу. Вот пример:

Я переименовал оригинальный файл 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".

Как это сделать?

Ответ 1

Как насчет 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";
    }
}

Ответ 2

Вы можете расширить класс без изменения его существующего поведения:

class A {
  public function foo(){

  }
}

class MySubClassOfA extends A {
  public function bar(){

  }
}

Вы можете добавить свои собственные методы в MySubClassOfA, т.е. bar(). Вы можете вызвать метод foo на MySubClassOfA, и он будет таким же, если вы не определяете метод, называемый foo в MySubClassOfA.

Ответ 3

Я предполагаю, что у вас нет выбора, кроме как добавить одну строку кода "namespace xxx;" поверх всех ваших файлов. Может понадобиться следующий CLI-интерфейс CLI script.

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