Динамическое создание классов в php

Динамическое создание классов в php

PHP’s implementation of namespaces is influenced by its dynamic nature as a programming language. Thus, to convert code like the following example into namespaced code:

Example #1 Dynamically accessing elements

class classname
function __construct ()
echo __METHOD__ , «\n» ;
>
>
function funcname ()
echo __FUNCTION__ , «\n» ;
>
const constname = «global» ;

$a = ‘classname’ ;
$obj = new $a ; // prints classname::__construct
$b = ‘funcname’ ;
$b (); // prints funcname
echo constant ( ‘constname’ ), «\n» ; // prints global
?>

One must use the fully qualified name (class name with namespace prefix). Note that because there is no difference between a qualified and a fully qualified Name inside a dynamic class name, function name, or constant name, the leading backslash is not necessary.

Example #2 Dynamically accessing namespaced elements

namespace namespacename ;
class classname
function __construct ()
echo __METHOD__ , «\n» ;
>
>
function funcname ()
echo __FUNCTION__ , «\n» ;
>
const constname = «namespaced» ;

/* note that if using double quotes, «\\namespacename\\classname» must be used */
$a = ‘\namespacename\classname’ ;
$obj = new $a ; // prints namespacename\classname::__construct
$a = ‘namespacename\classname’ ;
$obj = new $a ; // also prints namespacename\classname::__construct
$b = ‘namespacename\funcname’ ;
$b (); // prints namespacename\funcname
$b = ‘\namespacename\funcname’ ;
$b (); // also prints namespacename\funcname
echo constant ( ‘\namespacename\constname’ ), «\n» ; // prints namespaced
echo constant ( ‘namespacename\constname’ ), «\n» ; // also prints namespaced
?>

User Contributed Notes 8 notes

When extending a class from another namespace that should instantiate a class from within the current namespace, you need to pass on the namespace.

namespace foo ;
class A public function factory () return new C ;
>
>
class C public function tell () echo «foo» ;
>
>
?>

namespace bar ;
class B extends \ foo \ A <>
class C public function tell () echo «bar» ;
>
>
?>

include «File1.php» ;
include «File2.php» ;
$b = new bar \ B ;
$c = $b -> factory ();
$c -> tell (); // «foo» but you want «bar»
?>

You need to do it like this:

When extending a class from another namespace that should instantiate a class from within the current namespace, you need to pass on the namespace.

namespace foo ;
class A protected $namespace = __NAMESPACE__ ;
public function factory () $c = $this -> namespace . ‘\C’ ;
return new $c ;
>
>
class C public function tell () echo «foo» ;
>
>
?>

namespace bar ;
class B extends \ foo \ A protected $namespace = __NAMESPACE__ ;
>
class C public function tell () echo «bar» ;
>
>
?>

include «File1.php» ;
include «File2.php» ;
$b = new bar \ B ;
$c = $b -> factory ();
$c -> tell (); // «bar»
?>

(it seems that the namespace-backslashes are stripped from the source code in the preview, maybe it works in the main view. If not: fooA was written as \foo\A and barB as bar\B)

Important to know is that you need to use the *fully qualified name* in a dynamic class name. Here is an example that emphasizes the difference between a dynamic class name and a normal class name.

namespace namespacename \ foo ;

class classname
<
function __construct ()
<
echo ‘bar’ ;
>
>

$a = ‘\namespacename\foo\classname’ ; // Works, is fully qualified name
$b = ‘namespacename\foo\classname’ ; // Works, is treated as it was with a prefixed «\»
$c = ‘foo\classname’ ; // Will not work, it should be the fully qualified name

// Use dynamic class name
new $a ; // bar
new $b ; // bar
new $c ; // [500]: / — Uncaught Error: Class ‘foo\classname’ not found in

// Use normal class name
new \ namespacename \ foo \ classname ; // bar
new namespacename \ foo \ classname ; // [500]: / — Uncaught Error: Class ‘namespacename\foo\namespacename\foo\classname’ not found
new foo \ classname ; // [500]: / — Uncaught Error: Class ‘namespacename\foo\foo\classname’ not found

Be careful when using dynamic accessing namespaced elements. If you use double-quote backslashes will be parsed as escape character.

$a = «\namespacename\classname» ; //Invalid use and Fatal error.
$a = «\\namespacename\\classname» ; //Valid use.
$a = ‘\namespacename\classname’ ; //Valid use.
?>

Please be aware of FQCN (Full Qualified Class Name) point.
Many people will have troubles with this:

function factory ( $class ) <
return new $class ;
>

// File2.php
$bar = \ foo \ factory ( ‘Bar’ ); // Will try to instantiate \Bar, not \foo\Bar

?>

To fix that, and also incorporate a 2 step namespace resolution, you can check for \ as first char of $class, and if not present, build manually the FQCN:

function factory ( $class ) <
if ( $class [ 0 ] != ‘\\’ ) <
echo ‘->’ ;
$class = ‘\\’ . __NAMESPACE__ . ‘\\’ . $class ;
>

// File2.php
$bar = \ foo \ factory ( ‘Bar’ ); // Will correctly instantiate \foo\Bar

$bar2 = \ foo \ factory ( ‘\anotherfoo\Bar’ ); // Wil correctly instantiate \anotherfoo\Bar

Case you are trying call a static method that’s the way to go:

class myClass
public static function myMethod ()
return «You did it!\n» ;
>
>

$foo = «myClass» ;
$bar = «myMethod» ;

echo $foo :: $bar (); // prints «You did it!»;
?>

It might make it more clear if said this way:

One must note that when using a dynamic class name, function name or constant name, the «current namespace», as in http://www.php.net/manual/en/language.namespaces.basics.php is global namespace.

One situation that dynamic class names are used is in ‘factory’ pattern. Thus, add the desired namespace of your target class before the variable name.

namespaced.php
// namespaced.php
namespace Mypackage ;
class Foo public function factory ( $name , $global = FALSE )
if ( $global )
$class = $name ;
else
$class = ‘Mypackage\\’ . $name ;
return new $class ;
>
>

class A function __construct ()
echo __METHOD__ . «
\n» ;
>
>
class B function __construct ()
echo __METHOD__ . «
\n» ;
>
>
?>

global.php
// global.php
class A function __construct ()
echo __METHOD__ ;
>
>
?>

index.php
// index.php
namespace Mypackage ;
include( ‘namespaced.php’ );
include( ‘global.php’ );

$a = $foo -> factory ( ‘A’ ); // Mypackage\A::__construct
$b = $foo -> factory ( ‘B’ ); // Mypackage\B::__construct

$a2 = $foo -> factory ( ‘A’ , TRUE ); // A::__construct
$b2 = $foo -> factory ( ‘B’ , TRUE ); // Will produce : Fatal error: Class ‘B’ not found in . namespaced.php on line .
?>

as noted by guilhermeblanco at php dot net,

public function create ( $class ) return new $class ();
>
>

$foofact = new fact ();
$bar = $foofact -> create ( ‘bar’ ); // attempts to create \bar
// even though foofact and
// bar reside in \foo

//single or double quotes with single or double backslash in dynamic namespace class.

namespace Country_Name class Mexico function __construct ()echo __METHOD__ , «
» ;
>
>

$a = ‘Country_Name\Mexico’ ; //Country_Name\Mexico::__construct
$a = «Country_Name\Mexico» ;
//Country_Name\Mexico::__construct
$a = ‘\Country_Name\Mexico’ ;
//Country_Name\Mexico::__construct
$a = «\Country_Name\Mexico» ;
//Country_Name\Mexico::__construct
$a = «\\Country_Name\\Mexico» ;
//Country_Name\Mexico::__construct
$o = new $a ;

/* if your namespace name or class name start with lowercase n then you should be alart about the use of single or double quotes with backslash */

namespace name_of_country class Japan function __construct ()
echo __METHOD__ , «
» ;
>

$a = ‘name_of_country\Japan’ ;
//name_of_country\Japan::__construct
$a = «name_of_country\Japan» ;
//name_of_country\Japan::__construct
$a = ‘\name_of_country\Japan’ ;
//name_of_country\Japan::__construct
//$a = «\name_of_country\Japan»;
//Fatal error: Uncaught Error: Class ‘ ame_of_country\Japan’ not found
//In this statement «\name_of_country\Japan» means -first letter n with «\ == new line(«\n). for fix it we can use double back slash or single quotes with single backslash.
$a = «\\name_of_country\\Japan» ;
//name_of_country\Japan::__construct
$o = new $a ;
>

namespace Country_Name class name function __construct ()echo __METHOD__ , «
» ;
>
>

$a = ‘Country_Name\name’ ;
//Country_Name\Norway::__construct
$a = «Country_Name\name» ;
//Country_Name\Norway::__construct
$a = ‘\Country_Name\name’ ;
//Country_Name\Norway::__construct
//$a = «\Country_Name\name»;
//Fatal error: Uncaught Error: Class ‘\Country_Name ame’ not found

//In this statement «\Country_Name\name» at class name’s first letter n with «\ == new line(«\n). for fix it we can use double back slash or single quotes with single backslash
$a = «\\Country_Name\\name» ;
//Country_Name\name::__construct
$o = new $a ;

//»\n == new line are case insensitive so «\N could not affected

Оцените статью