Пространство имен 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]);
}
}
?>