To get the name of a subclass, I use get_called_class().
What should I use to get the file path of a subclass?
Use Reflection, specifically ReflectionClass::getFileName(). How you instantiate your ReflectionClass depends entirely on the current scope, eg
// globally
$reflectionClass = new ReflectionClass('SubClassName');
// within the sub class
$reflectionClass = new ReflectionClass(__CLASS__);
// within either sub or parent class in a static method
$reflectionClass = new ReflectionClass(get_called_class());
// within either sub or parent class, provided the instance is a sub class
$reflectionClass = new RelfectionObject($this);
// filename
$fn = $reflectionClass->getFileName();
// what I assume you mean by "path"
$path = dirname($fn);
Related
I have two classes.
I want to check if a class is an instance of another class without initializing either of them.
With the function is_subclass_of and when using instanceOf you have to initialize the sub class.
<?php
$classPath = 'app/foo/bar';
$subClassPath = 'app/foo/foo'; // Inherits from $classPath
// This is what I want to do but doesn't work.
echo $subClassPath instanceOf $classPath;
// Works
echo (new $subClassPath()) instanceOf $classPath;
I found the problem.
is_subclass_of requires your slashes to go the other way.
$classPath = 'app\foo\bar';
$subClassPath = 'app\foo\foo'; // Inherits from $classPath
// Works
echo is_subclass_of($subClassPath $classPath);
I'm using PHP 7.1.11
Consider below code :
<?php
class Test {
static public function getNew() {
return new static;
}
}
class Child extends Test {}
$obj1 = new Test();
$obj2 = new $obj1;
?>
Above code snippet has been taken from the PHP Manual.
From the above code I'm not able to understand why and how the new keyword is being used with the existing object of a class Test?
What's the intention behind doing like this?
Is this kind of usage of new keyword recommended?
If you really want to assign an already existing object of a class to some variable then can't it be done by simply writing the statement $obj2 = $obj1;?
What's the difference between below two statements? Which one is better and should be preferred?
$obj2 = new $obj1;
$obj2 = $obj1;
$obj2 = new $obj1; (creates a new instance of an object of the same class as $obj1) !== $obj2 = $obj1; (which creates $obj2 a reference to $obj1) !== $obj2 = clone $obj1; (which creates a new $obj2 with all the same property values as the original but as a new object instance)
For the 3 different cases that I cited in my comments above, let's create a simple class and instantiate it:
class User {
public $firstname;
public $lastname;
public function __construct($firstname = 'TEST', $lastname = 'USER') {
$this->firstname = $firstname;
$this->lastname = $lastname;
}
public function getName() {
return implode(' ', [$this->firstname, $this->lastname]);
}
}
// original instance of a User
$obj1 = new User('Mark', 'Baker');
var_dump($obj1->getName()); // Mark Baker
Now if we simply assign a new variable to the original, we're setting a pointer to the original (because it's an object), similar to a reference
// Simply set reference to our original User
$obj2 = $obj1;
var_dump($obj2->getName()); // Mark Baker
// And if we change properties of the instance, it changes for both because it's a reference
$obj2->firstname = 'David Mark';
var_dump($obj2->getName()); // David Mark Baker
var_dump($obj1->getName()); // David Mark Baker
Any changes to either will be reflected in the other, because they are pointing to the same object instance
If we use clone, then we're creating a brand new object instance, but already populated with the property values from the original
// Clone the original object, this will create a new instance but will inherit property values of the original
$obj3 = clone $obj1;
var_dump($obj3->getName()); // David Mark Baker
// But changing properties of the clone won't affect the original in any way
$obj3->firstname = 'Mark';
var_dump($obj3->getName()); // Mark Baker
var_dump($obj1->getName()); // David Mark Baker
Now if we change properties of the original, it won't affect the clone (or vice versa) because they are unique instances.
The we have the third case, where we're using new with an instance rather than class name.
// Now create a new instance of the same type of object as your original User
// If we had mandatory constructor arguments, then we'd have to provide them $obj4 = new $obj1('a', 'b');
// But because they're optional, we can get away with allowing the defaults
$obj4 = new $obj1;
var_dump($obj4->getName()); // TEST USER
If we didn't know what class type $obj1 was, then it doesn't matter (though it would have been easy enough to find out). This creates a brand new instance of whatever class $obj1 was, without the property inheritance that clone gives, nor is it reference like $obj2 = $obj1 gave..... it still calls the constructor, so we have to pass any mandatory constructor arguments (or get an error).
The new operator always creates a new instance of an object. It takes one argument, which can be a hard-coded class name:
$newObject = new MyClass();
Or a variable that contains a class name:
$className = 'MyClass';
$newObject = new $className();
Or an existing instance of an object of the type you want to create:
$oldObject = new MyClass();
$newObject = new $oldObject(); // Same as using "new MyClass();"
You'll probably never use the third case.
If I have a class name in $name, how can I create an object of type \folder\$name? Ideally I'd like to interpolate the $name so that I can create the object with just a single line of code.
The following doesn't seem to work:
$obj = new \folder\$name();
The problem is youre trying to use a variable as part of a FQCN. You cannot do that. The FQCN can be a variable itself like:
$fqcn = '\folder\classname';
$obj = new $fqcn();
Or you can delcare the namespace at the top of the file:
namespace folder;
$fqcn = 'classname';
$obj = new $fqcn;
Or if the file belongs to another namespace you can use the class to "localize" it:
namespace mynamespace;
use folder\classname;
$fqcn = 'classname';
$obj = new $fqcn();
A more concrete example of something i assume to be similar to what you are trying to do:
namespace App\WebCrawler;
// any local uses of the File class actually refer to
// \App\StorageFile instead of \App\WebCrawler\File
use App\Storage\File;
// if we didnt use the "as" keyword here we would have a conflict
// because the final component of our storage and cache have the same name
use App\Cache\File as FileCache;
class Client {
// the FQCN of this class is \App\WebCrawler\Client
protected $httpClient;
protected $storage;
protected $cache
static protected $clients = array(
'symfony' => '\Symfony\Component\HttpKernel\Client',
'zend' => '\Zend_Http_Client',
);
public function __construct($client = 'symfony') {
if (!isset(self::$clients[$client])) {
throw new Exception("Client \"$client\" is not registered.");
}
// this would be the FQCN referenced by the array element
$this->httpClient = new self::$clients[$client]();
// because of the use statement up top this FQCN would be
// \App\Storage\File
$this->storage = new File();
// because of the use statement this FQCN would be
// \App\Cache\File
$this->cache = new FileCache();
}
public static function registerHttpClient($name, $fqcn) {
self::$clients[$name] = $fqcn;
}
}
You can read in more detail here: http://php.net/manual/en/language.namespaces.dynamic.php
Shouldn't it be
new \folder\$arr[0];
and not
new \folder\$arr[0]();
Also, I'm not too familiar with PHP, and I've never see this syntax before. What I suggest is:
namespace \folder;
$obj = new $arr[0];
I'm not sure if you can do it with just one line and without namespaces.
I'm trying to create an instance of an object but the object class name is set by hand.
in config.php:
define('DIRECTORY', 'RaptorDirectory');
in the class file:
$this->directory = new DIRECTORY; // <--- how do I use the constant there?
I'm doing this because DIRECTORY might change to a different class (e.g., LDAPDirectory)
You can't use a constant there but you can use a variable, eg
$class = DIRECTORY;
$this->directory = new $class;
If I declared a class in a controller and want to use it in a model without passing the class' pointer, how can I redeclare that class without the "Fatal error: Class already declared"? If I use the get_declared_classes() function, I see that the class is declared, but how can I get the pointer to that class so that I can use it in the model?
Basically, how can I use a class that's been declared but with no pointer.
Any help would be greatly appreciated.
Thanks in advance!
EDIT: Maybe the word "pointer" was misused. Here's some code
// Controller...one file
$class = new Class();
$model = $this->load_model('example.php');
$model->dosomething();
// Model...example.php
function dosomething() {
// I want to access the class here. Is it only possible to do this by
// passing a $class parameter to the function or can I do it without
// passing it as a variable?
}
I think you're mixing terminology. There's no concept of a pointer anywhere in PHP. References are similar concepts, but that's another topic.
What I think you're trying to do, is use a variable to indicate the class in the model. So, you can use a string. So let's say you want to tell the model to use class Foo, you could inject the class name into the model:
$model = new Model('foo');
Then, inside the constructor:
public function __construct($class) {
$this->className = $class;
}
Then, when you want to use it, just call new:
$class = $this->className;
$obj = new $class();
But note that it has nothing to do with object scope. So you could do it anywhere:
$class = 'Foo';
$obj = new $class;