mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
ENHANCEMENT Allow ClassManifest to handle classes with namespaces, or that extend classes in namspaces or that implement interfaces in namespaces.
This commit is contained in:
parent
bad1b88942
commit
3e6a91a07f
@ -40,19 +40,59 @@ class SS_ClassManifest {
|
|||||||
3 => T_WHITESPACE,
|
3 => T_WHITESPACE,
|
||||||
4 => T_EXTENDS,
|
4 => T_EXTENDS,
|
||||||
5 => T_WHITESPACE,
|
5 => T_WHITESPACE,
|
||||||
6 => array(T_STRING, 'save_to' => 'extends', 'can_jump_to' => 14),
|
6 => array(T_STRING, 'save_to' => 'extends[]', 'can_jump_to' => 14),
|
||||||
7 => T_WHITESPACE,
|
7 => T_WHITESPACE,
|
||||||
8 => T_IMPLEMENTS,
|
8 => T_IMPLEMENTS,
|
||||||
9 => T_WHITESPACE,
|
9 => T_WHITESPACE,
|
||||||
10 => array(T_STRING, 'can_jump_to' => 14, 'save_to' => 'interfaces[]'),
|
10 => array(T_STRING, 'can_jump_to' => 14, 'save_to' => 'interfaces[]'),
|
||||||
11 => array(T_WHITESPACE, 'optional' => true),
|
11 => array(T_WHITESPACE, 'optional' => true),
|
||||||
12 => array(',', 'can_jump_to' => 10),
|
12 => array(',', 'can_jump_to' => 10, 'save_to' => 'interfaces[]'),
|
||||||
13 => array(T_WHITESPACE, 'can_jump_to' => 10),
|
13 => array(T_WHITESPACE, 'can_jump_to' => 10),
|
||||||
14 => array(T_WHITESPACE, 'optional' => true),
|
14 => array(T_WHITESPACE, 'optional' => true),
|
||||||
15 => '{',
|
15 => '{',
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TokenisedRegularExpression
|
||||||
|
*/
|
||||||
|
public static function get_namespaced_class_parser() {
|
||||||
|
return new TokenisedRegularExpression(array(
|
||||||
|
0 => T_CLASS,
|
||||||
|
1 => T_WHITESPACE,
|
||||||
|
2 => array(T_STRING, 'can_jump_to' => array(8, 16), 'save_to' => 'className'),
|
||||||
|
3 => T_WHITESPACE,
|
||||||
|
4 => T_EXTENDS,
|
||||||
|
5 => T_WHITESPACE,
|
||||||
|
6 => array(T_NS_SEPARATOR, 'save_to' => 'extends[]', 'optional' => true),
|
||||||
|
7 => array(T_STRING, 'save_to' => 'extends[]', 'can_jump_to' => array(6, 16)),
|
||||||
|
8 => T_WHITESPACE,
|
||||||
|
9 => T_IMPLEMENTS,
|
||||||
|
10 => T_WHITESPACE,
|
||||||
|
11 => array(T_NS_SEPARATOR, 'save_to' => 'interfaces[]', 'optional' => true),
|
||||||
|
12 => array(T_STRING, 'can_jump_to' => array(11, 16), 'save_to' => 'interfaces[]'),
|
||||||
|
13 => array(T_WHITESPACE, 'optional' => true),
|
||||||
|
14 => array(',', 'can_jump_to' => 11, 'save_to' => 'interfaces[]'),
|
||||||
|
15 => array(T_WHITESPACE, 'can_jump_to' => 11),
|
||||||
|
16 => array(T_WHITESPACE, 'optional' => true),
|
||||||
|
17 => '{',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TokenisedRegularExpression
|
||||||
|
*/
|
||||||
|
public static function get_namespace_parser() {
|
||||||
|
return new TokenisedRegularExpression(array(
|
||||||
|
0 => T_NAMESPACE,
|
||||||
|
1 => T_WHITESPACE,
|
||||||
|
2 => array(T_NS_SEPARATOR, 'save_to' => 'namespaceName[]', 'optional' => true),
|
||||||
|
3 => array(T_STRING, 'save_to' => 'namespaceName[]', 'can_jump_to' => 2),
|
||||||
|
4 => array(T_WHITESPACE, 'optional' => true),
|
||||||
|
5 => ';',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return TokenisedRegularExpression
|
* @return TokenisedRegularExpression
|
||||||
*/
|
*/
|
||||||
@ -267,6 +307,7 @@ class SS_ClassManifest {
|
|||||||
|
|
||||||
$classes = null;
|
$classes = null;
|
||||||
$interfaces = null;
|
$interfaces = null;
|
||||||
|
$namespace = null;
|
||||||
|
|
||||||
// The results of individual file parses are cached, since only a few
|
// The results of individual file parses are cached, since only a few
|
||||||
// files will have changed and TokenisedRegularExpression is quite
|
// files will have changed and TokenisedRegularExpression is quite
|
||||||
@ -277,30 +318,48 @@ class SS_ClassManifest {
|
|||||||
|
|
||||||
if ($data = $this->cache->load($key)) {
|
if ($data = $this->cache->load($key)) {
|
||||||
$valid = (
|
$valid = (
|
||||||
isset($data['classes']) && isset($data['interfaces'])
|
isset($data['classes']) && isset($data['interfaces']) && isset($data['namespace'])
|
||||||
&& is_array($data['classes']) && is_array($data['interfaces'])
|
&& is_array($data['classes']) && is_array($data['interfaces']) && is_array($data['namespace'])
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
$classes = $data['classes'];
|
$classes = $data['classes'];
|
||||||
$interfaces = $data['interfaces'];
|
$interfaces = $data['interfaces'];
|
||||||
|
$namespace = $data['namespace'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$classes) {
|
if (!$classes) {
|
||||||
$tokens = token_get_all($file);
|
$tokens = token_get_all($file);
|
||||||
|
if(version_compare(PHP_VERSION, '5.3', '>=')) {
|
||||||
|
$classes = self::get_namespaced_class_parser()->findAll($tokens);
|
||||||
|
$namespace = self::get_namespace_parser()->findAll($tokens);
|
||||||
|
if($namespace) {
|
||||||
|
$namespace = implode('', $namespace[0]['namespaceName']) . '\\';
|
||||||
|
} else {
|
||||||
|
$namespace = '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$classes = self::get_class_parser()->findAll($tokens);
|
$classes = self::get_class_parser()->findAll($tokens);
|
||||||
|
$namespace = '';
|
||||||
|
}
|
||||||
$interfaces = self::get_interface_parser()->findAll($tokens);
|
$interfaces = self::get_interface_parser()->findAll($tokens);
|
||||||
|
|
||||||
$cache = array('classes' => $classes, 'interfaces' => $interfaces);
|
$cache = array('classes' => $classes, 'interfaces' => $interfaces, 'namespace' => $namespace);
|
||||||
$this->cache->save($cache, $key, array('fileparse'));
|
$this->cache->save($cache, $key, array('fileparse'));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($classes as $class) {
|
foreach ($classes as $class) {
|
||||||
$name = $class['className'];
|
$name = $namespace . $class['className'];
|
||||||
$extends = isset($class['extends']) ? $class['extends'] : null;
|
$extends = isset($class['extends']) ? implode('', $class['extends']) : null;
|
||||||
$implements = isset($class['interfaces']) ? $class['interfaces'] : null;
|
$implements = isset($class['interfaces']) ? $class['interfaces'] : null;
|
||||||
|
|
||||||
|
if($extends && $extends[0] != '/\\') {
|
||||||
|
$extends = $namespace . $extends;
|
||||||
|
} elseif($extends) {
|
||||||
|
$extends = substr($extends, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (array_key_exists($name, $this->classes)) {
|
if (array_key_exists($name, $this->classes)) {
|
||||||
throw new Exception(sprintf(
|
throw new Exception(sprintf(
|
||||||
'There are two files containing the "%s" class: "%s" and "%s"',
|
'There are two files containing the "%s" class: "%s" and "%s"',
|
||||||
@ -322,7 +381,19 @@ class SS_ClassManifest {
|
|||||||
$this->roots[] = $name;
|
$this->roots[] = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($implements) foreach ($implements as $interface) {
|
if ($implements) {
|
||||||
|
$interface = $namespace;
|
||||||
|
for($i = 0; $i < count($implements); ++$i) {
|
||||||
|
if($implements[$i] == ',') {
|
||||||
|
$interface = $namespace;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($implements[$i] == '\\' && $interface == $namespace) {
|
||||||
|
$interface = '';
|
||||||
|
} else {
|
||||||
|
$interface .= $implements[$i];
|
||||||
|
}
|
||||||
|
if($i == count($implements)-1 || $implements[$i+1] == ',') {
|
||||||
$interface = strtolower($interface);
|
$interface = strtolower($interface);
|
||||||
|
|
||||||
if (!isset($this->implementors[$interface])) {
|
if (!isset($this->implementors[$interface])) {
|
||||||
@ -332,9 +403,11 @@ class SS_ClassManifest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($interfaces as $interface) {
|
foreach ($interfaces as $interface) {
|
||||||
$this->interfaces[strtolower($interface['interfaceName'])] = $pathname;
|
$this->interfaces[strtolower($namespace . $interface['interfaceName'])] = $pathname;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
114
tests/core/manifest/NamespacedClassManifestTest.php
Normal file
114
tests/core/manifest/NamespacedClassManifestTest.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Tests for the {@link SS_ClassManifest} class.
|
||||||
|
*
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage tests
|
||||||
|
*/
|
||||||
|
class NamespacedClassManifestTest extends SapphireTest {
|
||||||
|
|
||||||
|
protected $base;
|
||||||
|
protected $manifest;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->base = dirname(__FILE__) . '/fixtures/namespaced_classmanifest';
|
||||||
|
$this->manifest = new SS_ClassManifest($this->base, false, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetItemPath() {
|
||||||
|
$expect = array(
|
||||||
|
'SAPPHIRE\TEST\CLASSA' => 'module/classes/ClassA.php',
|
||||||
|
'Sapphire\Test\ClassA' => 'module/classes/ClassA.php',
|
||||||
|
'sapphire\test\classa' => 'module/classes/ClassA.php',
|
||||||
|
'SAPPHIRE\TEST\INTERFACEA' => 'module/interfaces/InterfaceA.php',
|
||||||
|
'Sapphire\Test\InterfaceA' => 'module/interfaces/InterfaceA.php',
|
||||||
|
'sapphire\test\interfacea' => 'module/interfaces/InterfaceA.php'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($expect as $name => $path) {
|
||||||
|
$this->assertEquals("{$this->base}/$path", $this->manifest->getItemPath($name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetClasses() {
|
||||||
|
$expect = array(
|
||||||
|
'sapphire\test\classa' => "{$this->base}/module/classes/ClassA.php",
|
||||||
|
'sapphire\test\classb' => "{$this->base}/module/classes/ClassB.php",
|
||||||
|
'sapphire\test\classc' => "{$this->base}/module/classes/ClassC.php",
|
||||||
|
'sapphire\test\classd' => "{$this->base}/module/classes/ClassD.php",
|
||||||
|
'sapphire\test\classe' => "{$this->base}/module/classes/ClassE.php",
|
||||||
|
'sapphire\test\classf' => "{$this->base}/module/classes/ClassF.php",
|
||||||
|
'sapphire\test\classg' => "{$this->base}/module/classes/ClassG.php"
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expect, $this->manifest->getClasses());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetClassNames() {
|
||||||
|
$this->assertEquals(
|
||||||
|
array('sapphire\test\classa', 'sapphire\test\classb', 'sapphire\test\classc', 'sapphire\test\classd', 'sapphire\test\classe', 'sapphire\test\classf', 'sapphire\test\classg'),
|
||||||
|
$this->manifest->getClassNames());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetDescendants() {
|
||||||
|
$expect = array(
|
||||||
|
'sapphire\test\classa' => array('sapphire\test\ClassB')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expect, $this->manifest->getDescendants());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetDescendantsOf() {
|
||||||
|
$expect = array(
|
||||||
|
'SAPPHIRE\TEST\CLASSA' => array('sapphire\test\ClassB'),
|
||||||
|
'sapphire\test\classa' => array('sapphire\test\ClassB'),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($expect as $class => $desc) {
|
||||||
|
$this->assertEquals($desc, $this->manifest->getDescendantsOf($class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetInterfaces() {
|
||||||
|
$expect = array(
|
||||||
|
'sapphire\test\interfacea' => "{$this->base}/module/interfaces/InterfaceA.php",
|
||||||
|
);
|
||||||
|
$this->assertEquals($expect, $this->manifest->getInterfaces());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetImplementors() {
|
||||||
|
$expect = array(
|
||||||
|
'sapphire\test\interfacea' => array('sapphire\test\ClassE'),
|
||||||
|
'interfacea' => array('sapphire\test\ClassF'),
|
||||||
|
'sapphire\test\subtest\interfacea' => array('sapphire\test\ClassG')
|
||||||
|
);
|
||||||
|
$this->assertEquals($expect, $this->manifest->getImplementors());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetImplementorsOf() {
|
||||||
|
$expect = array(
|
||||||
|
'SAPPHIRE\TEST\INTERFACEA' => array('sapphire\test\ClassE'),
|
||||||
|
'sapphire\test\interfacea' => array('sapphire\test\ClassE'),
|
||||||
|
'INTERFACEA' => array('sapphire\test\ClassF'),
|
||||||
|
'interfacea' => array('sapphire\test\ClassF'),
|
||||||
|
'SAPPHIRE\TEST\SUBTEST\INTERFACEA' => array('sapphire\test\ClassG'),
|
||||||
|
'sapphire\test\subtest\interfacea' => array('sapphire\test\ClassG'),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($expect as $interface => $impl) {
|
||||||
|
$this->assertEquals($impl, $this->manifest->getImplementorsOf($interface));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetConfigs() {
|
||||||
|
$expect = array("{$this->base}/module/_config.php");
|
||||||
|
$this->assertEquals($expect, $this->manifest->getConfigs());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetModules() {
|
||||||
|
$expect = array("module" => "{$this->base}/module");
|
||||||
|
$this->assertEquals($expect, $this->manifest->getModules());
|
||||||
|
}
|
||||||
|
}
|
@ -47,6 +47,45 @@ interface InterfaceC extends InterfaceA, InterfaceB {
|
|||||||
}
|
}
|
||||||
interface InterfaceD extends InterfaceA, InterfaceB, InterfaceC {
|
interface InterfaceD extends InterfaceA, InterfaceB, InterfaceC {
|
||||||
}
|
}
|
||||||
|
?>
|
||||||
|
PHP
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNamespaceTokens() {
|
||||||
|
return token_get_all(<<<PHP
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sapphire\\test;
|
||||||
|
|
||||||
|
class ClassA {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassB extends ParentClassB {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassC extends \\ParentClassC {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassD extends subtest\\ParentClassD {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassE implements InterfaceE {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassF implements \\InterfaceF {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassG implements subtest\\InterfaceG {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
PHP
|
PHP
|
||||||
);
|
);
|
||||||
@ -65,23 +104,53 @@ PHP
|
|||||||
$this->assertArrayHasKey('ClassB', $classes);
|
$this->assertArrayHasKey('ClassB', $classes);
|
||||||
|
|
||||||
$this->assertArrayHasKey('ClassC', $classes);
|
$this->assertArrayHasKey('ClassC', $classes);
|
||||||
$this->assertEquals('ParentClassC', $classes['ClassC']['extends']);
|
$this->assertEquals(array('ParentClassC'), $classes['ClassC']['extends']);
|
||||||
|
|
||||||
$this->assertArrayHasKey('ClassD', $classes);
|
$this->assertArrayHasKey('ClassD', $classes);
|
||||||
$this->assertEquals('ParentClassD', $classes['ClassD']['extends']);
|
$this->assertEquals(array('ParentClassD'), $classes['ClassD']['extends']);
|
||||||
$this->assertContains('InterfaceA', $classes['ClassD']['interfaces']);
|
$this->assertContains('InterfaceA', $classes['ClassD']['interfaces']);
|
||||||
|
|
||||||
$this->assertArrayHasKey('ClassE', $classes);
|
$this->assertArrayHasKey('ClassE', $classes);
|
||||||
$this->assertEquals('ParentClassE', $classes['ClassE']['extends']);
|
$this->assertEquals(array('ParentClassE'), $classes['ClassE']['extends']);
|
||||||
$this->assertContains('InterfaceA', $classes['ClassE']['interfaces']);
|
$this->assertContains('InterfaceA', $classes['ClassE']['interfaces']);
|
||||||
$this->assertContains('InterfaceB', $classes['ClassE']['interfaces']);
|
$this->assertContains('InterfaceB', $classes['ClassE']['interfaces']);
|
||||||
|
|
||||||
$this->assertArrayHasKey('ClassF', $classes);
|
$this->assertArrayHasKey('ClassF', $classes);
|
||||||
$this->assertEquals('ParentClassF', $classes['ClassF']['extends']);
|
$this->assertEquals(array('ParentClassF'), $classes['ClassF']['extends']);
|
||||||
$this->assertContains('InterfaceA', $classes['ClassF']['interfaces']);
|
$this->assertContains('InterfaceA', $classes['ClassF']['interfaces']);
|
||||||
$this->assertContains('InterfaceB', $classes['ClassF']['interfaces']);
|
$this->assertContains('InterfaceB', $classes['ClassF']['interfaces']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testNamesapcedClassDefParser() {
|
||||||
|
if(version_compare(PHP_VERSION, '5.3', '<')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$parser = SS_ClassManifest::get_namespaced_class_parser();
|
||||||
|
|
||||||
|
$tokens = $this->getNamespaceTokens();
|
||||||
|
|
||||||
|
$matches = $parser->findAll($tokens);
|
||||||
|
|
||||||
|
$classes = array();
|
||||||
|
if($matches) foreach($matches as $match) $classes[$match['className']] = $match;
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('ClassA', $classes);
|
||||||
|
$this->assertArrayHasKey('ClassB', $classes);
|
||||||
|
$this->assertEquals(array('ParentClassB'), $classes['ClassB']['extends']);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('ClassC', $classes);
|
||||||
|
$this->assertEquals(array('\\', 'ParentClassC'), $classes['ClassC']['extends']);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('ClassD', $classes);
|
||||||
|
$this->assertEquals(array('subtest', '\\', 'ParentClassD'), $classes['ClassD']['extends']);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('ClassE', $classes);
|
||||||
|
$this->assertContains('InterfaceE', $classes['ClassE']['interfaces']);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('ClassF', $classes);
|
||||||
|
$this->assertEquals(array('\\', 'InterfaceF'), $classes['ClassF']['interfaces']);
|
||||||
|
}
|
||||||
|
|
||||||
function testInterfaceDefParser() {
|
function testInterfaceDefParser() {
|
||||||
$parser = SS_ClassManifest::get_interface_parser();
|
$parser = SS_ClassManifest::get_interface_parser();
|
||||||
|
|
||||||
@ -96,4 +165,20 @@ PHP
|
|||||||
$this->assertArrayHasKey('InterfaceC', $interfaces);
|
$this->assertArrayHasKey('InterfaceC', $interfaces);
|
||||||
$this->assertArrayHasKey('InterfaceD', $interfaces);
|
$this->assertArrayHasKey('InterfaceD', $interfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testNamespaceDefParser() {
|
||||||
|
if(version_compare(PHP_VERSION, '5.3', '<')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$parser = SS_ClassManifest::get_namespace_parser();
|
||||||
|
|
||||||
|
$namespacedTokens = $this->getNamespaceTokens();
|
||||||
|
$tokens = $this->getTokens();
|
||||||
|
|
||||||
|
$namespacedMatches = $parser->findAll($namespacedTokens);
|
||||||
|
$matches = $parser->findAll($tokens);
|
||||||
|
|
||||||
|
$this->assertEquals(array(), $matches);
|
||||||
|
$this->assertEquals(array('sapphire', '\\', 'test'), $namespacedMatches[0]['namespaceName']);
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace sapphire\test;
|
||||||
|
|
||||||
|
class ClassA { }
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace sapphire\test;
|
||||||
|
|
||||||
|
class ClassB extends ClassA { }
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace sapphire\test;
|
||||||
|
|
||||||
|
class ClassC extends \ClassA { }
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace sapphire\test;
|
||||||
|
|
||||||
|
class ClassD extends subtest\ClassC { }
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace sapphire\test;
|
||||||
|
|
||||||
|
class ClassE implements InterfaceA { }
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace sapphire\test;
|
||||||
|
|
||||||
|
class ClassF implements \InterfaceA { }
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace sapphire\test;
|
||||||
|
|
||||||
|
class ClassG implements subtest\InterfaceA { }
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace sapphire\test;
|
||||||
|
|
||||||
|
interface InterfaceA { }
|
Loading…
Reference in New Issue
Block a user