Using defined constants to create objects - php

Arbitrary PHP question, more/less out of curiosity. I apologize if this is a silly question.
$class = 'ClassName';
$object = new $class();
or
$object = $class::functionName();
This obviously works.
define(CLASS, 'ClassName');
$object = new CLASS();
or
$object = CLASS::functionName();
This does not work.
Just wondering if it is at all possible to use defined constants to create new objects. If not, I definitely understand why.

Well, you can do this:
define(MYCLASS, 'ClassName');
$class = MYCLASS;
$object = new $class();
...but as far as I know, you can't use the constant directly as in new MYCLASS(), because it will of course look for the class named MYCLASS.
Side note: You can't have constants with names that conflict with reserved words, like class or function, even if they are uppercased.
You could do something silly like this if for some reason you're doing this a lot:
function newClass($str, $args = NULL) {
return new $str($args);
}
$class = newClass(MYCLASS);
...but I don't really recommend it. I'd also guess that you probably don't need so many constants, or there's a more elegant way to do what you're doing that doesn't involve constants at all.

Related

Object creation is not working without using as a variable [duplicate]

This question about syntax/syntax capabilities in PHP. Take for example, using variables to store class names when declaring objects:
$className= 'myClass';
$obj = new $className;
I was wondering if there were some way to do the same with constants. Something along the lines of:
define('CLASS_NAME','myClass');
$obj = new {CLASS_NAME};
This doesn't work. Obviously I could just use a variable as an intermediary step, but I was mostly just wondering for edification purposes whether this was a formatting issue or if this is just not possible to do directly in this way.
You can't do this with a sensible expression in PHP, as u_mulder says.
You can do it in one line with reflection.
$obj = (new ReflectionClass(CLASS_NAME))->newInstance();
Any parameters need to go into the newInstance call.
This is a silly idea, not least because having variable behaviour depending on class names in strings probably means bad architecture. Don't do it. But you asked if it is possible, and yes, it is.
As class name (e.g. MyClass) can not be distinguished from constant name MyClass - your approach will not work.
You can do:
const CLASS_NAME = '\MyClass';
$className = CLASS_NAME;
$object = new $className;
With php >=8.0 you can do the following:
final class SomeService
{
private const HANDLER_CLASS = CustomHandler::class;
private HandlerInterface $handler;
public function process(): void
{
$this->handler = new (self::HANDLER_CLASS)();
}
}

Why changes on a class affects on other class?

Here is my code: Demo
class myclass1 {
public $myvariable;
}
$obj1 = new myclass1;
$obj2 = $obj1;
$obj1->myvariable = 'something';
echo $obj2->myvariable; //=> something
As you see, I've initialized something to the first object, but surprisingly it will be also applied on the second object. Why really? Actually I need to have two different value in $myvariable for both classes, not the same value.
How can I do that?
That's how OOP works. Actually all you need to know is about pass-by-reference. Take a look at this:
In your code, both $obj1 and $obj2 are using same memory point. So any change on $obj1 will be seen also on the $obj2. To separate them from each other you need to use clone:
$obj2 = clone $obj1;
By cloning an object you are actually making a copy of it. So the new object won't refer to the old one.

PHP How to get proper case class name

class Google_Model_SomeThing { ... }
$className = 'google_MODEL_something';
I can create instance of class base on $className. But what if I would like to get proper case class name from $className without creating instance?
I expect something like this:
echo func('google_MODEL_something'); // Google_Model_SomeThing
or
$className = 'google_MODEL_something';
echo $className::class; // Google_Model_SomeThing
Reflection is most likely a better option, but here is an alternative:
You could use get_declared_classes after calling class_exists($wrongCaseName) and find the class name in the array of declared classes.
Example:
$wrongCaseName = 'Some\classy\THIng';
class_exists($wrongCaseName); //so it gets autoloaded if not already done
$classes = get_declared_classes();
$map = array_combine(array_map('strtolower',$classes),$classes);
$proper = $map[strtolower($wrongCaseName)];
Performance
The reflection-based method, noted by l00k, is significantly faster, by about 3 times. I ran this version vs the reflection version on 500 different classes with randomly generated names & no code within them. The reflection-method took about 0.015 seconds to get the proper case for 500 classes, and my get_declared_classes method took about 0.050 seconds for 500 classes.
More details on my personal website. Tested on PHP 7.2.19 on my localhost server on my laptop.
I found code below working, but is it the simplest solution?
$className = 'google_MODEL_something';
$reflection = new ReflectionClass($className);
echo $reflection->getName(); // Google_Model_SomeThing
Well I would suggest to create an instance and then get the className using get_class().
$bar = new $classname();
$caseClassName = get_class($bar);

Get methods on a standard class?

Is there a way to get all the methods of an instantiated standard class object? I'm talking about an object that has some methods and properties on it, not a fresh stdClass object. ReflectionClass seems to work only on classes.
Try get_class_methods(), sounds like what you're describing, if I understand you correctly.
You can use get_object_vars to get a list of all of the properties, and then iterate over them (or array_filter them) and determine which of them is_callable:
$myClass = new StdClass;
$myClass->someFunc = function($a) {
return $a - 1;
};
$myClass->someProperty = 42;
$properties = get_object_vars($myClass);
$methods = array_filter($properties, 'is_callable');
I'm not sure if it's my 5.4.39 version of PHP or not, but using the above example and instead doing var_dump(get_class_methods($myClass)); as #Mike suggested returns an empty array.

"__class magic method" (mediating references to class names by a custom code)

You can redirect calls to some properties/functions by using __get, __call.
Is there a way to do it for classes?
I would like to convert all mentions of some_class_name in the code to, MY_VERSION_some_class_name (not only for one class, it's a pattern).
This would be easy if methods / properties were the target of this renaming policy.
Can you think of a way to do it for classes in PHP?
Edit: I need this for referencing to different variants of classes in different situations. I need one class name to be resolved to different variants of this class, depending on a condition known at runtime, and persistent through the whole session.
Thanks
p.s.
If you are curious why I want to do this, look at Maintaining variants of an application
You can't convert all mentions of some_class_name in the code to another class. However, you can use variables as class names:
$className = "MyClass";
$obj = new $className;
$className::myMethod();
All you have to do is change the variable and you will be using a different class. If you have to do this for a lot of classes, you might want to create some sort of factory for it.
$factory = System::getFactory();
$obj = $factory->getAuthObj();
Basically, the System class would return a different object based on what class needed to be used for that particular run time.
Aiden's untested approach: variable variables and generating a string:
<?php
$dog = "12";
function getDogClass($myNum)
{
global $dog;
// Do something dynamic here;
$dog = "Dog_" . $myNum;
return "dog";
}
class Dog_13rc1
{
function __construct()
{
printf("Woof!");
}
}
class Dog_12
{
function __construct()
{
printf("Grrrr");
}
}
$myObj = new ${getDogClass('13rc1')}();
?>
As long as the call to getDogClass() returns a string of the name of a variable in scope then you are good.
The output is woof.
This means the only refactoring you need is to find/replace occurences of the class name with that call.
But this is grim. and probably slow. Also, a maintenance/bug-tracking nightmare type of hack.
The magic function you want is __autoload:
function __autoload($class_name) {
// include your special class in here
include $class_name . '.php';
}
Read more here: http://php.net/manual/en/language.oop5.autoload.php

Categories