String containing function-line. How to echo in other file? - php

$str = "$obj = new class(); $obj->getSomeFunction();"
Is this possible? I am trying to develop a very dynamic platform to base my website off of.
Anyway to get this working? From a string by "echo $str;" it will make the object and run the function?

Instead of passing an object as a string, just create a new instance of your object. And once you've included a file.. All variables, objects, etc. exist in the file that includes that file.
Edit:
Instead of passing a class as a string, you can create classes dynamically:
<?php
class cc {
function __construct() {
echo 'hi!';
}
}
$type = 'cc';
$obj = new $type; // outputs "hi!"
?>
Alternatively you can use static classes:
<?php
class Foo {
public static function aStaticMethod() {
echo 'hi!';
}
}
Foo::aStaticMethod(); // outputs "hi!"
// or:
$classname = 'Foo';
$classname::aStaticMethod(); // outputs "hi!"
?>

I am in the process of writing my own mvc framework(as an learning project), and needed to dynamically create objects and call a method. I ended up using the reflection api in order to create a new instance of the object and then call the method. in this case i ended up passing an associative array that had two key/value pairs, the class name, and the method I wanted to call. I hope this helps.
$class = $command['class'];
$method = $command['method'];
try{
$reflectorClass = new ReflectionClass($class);
$reflectedInstance = $reflectorClass->newInstance($matches);
} catch (Exception $e) {
exceptionHandler::catchException($e);
}
try {
$reflectorMethod = new ReflectionMethod($reflectedInstance, $method);
$reflectorMethod->invoke($reflectedInstance);
} catch (Exception $e) {
exceptionHandler::catchException($e);
}

In PHP included files are executed when you call include() or require(). They follow variable scope rules and even allow you to return results as if the include was a function like so:
dynamicPlatform.php
<?php
$object = include('createObjAndDoStuff.php');
?>
createObjAndDoStuff.php
<?php
$obj = new class();
$obj->getSomeFunction();
return $obj;
?>
As #zerkms has pointed out, you probably should be using factories.
class Factory {
public static function someclass() {
include_once('./classes/someclass.php'); //Although some discourage the use of *_once() functions
$obj = new someclass();
$obj->getSomeFunction();
return $obj;
}
}
//And to get a new class instance
$object = Singleton::someclass();
Or pseudo-singletons with factories:
class SingletonFactory {
private static $someclass;
public static function someclass() {
if(!self::$someclass) {
include('./classes/someclass.php');
self::$someclass = new someclass();
self::$someclass->getSomeFunction();
}
return self::$someclass;
}
}

What you are searching for is eval but while it will do exactly what you are asking for, it's considered bad solution and can lead to messy code.
You can just include file that contains PHP code, or you can serialize meta data about the actions to be performed and then parse that data.
Depending on what you are trying to achieve, you may be interested in serializing objects in session as well as in Command Pattern (a way to encapsulate set of operations in object(s))

Related

Can I pass a type as parameter in PHP?

I'd like to pass (any type, not only PHP's primitives) Type as a function parameter. More like a C++'s template. Is it possible in PHP? imaginary code:
function foo(T a)
{
$output = new T();
//do something.
}
I tried pass the type name as string and then use settype() to the the variable to that type but settype() work only with PHP's primitives types. My goal is actually pass a class type as parameter.
If you want to instantiate something like the above, how about passing the classname as a string and then instantiating it!
function foo($obj_string)
{
$object = new $obj_string();
//do stuff with $object
}
I see that you already accepted an answer, but from the original post, it shows passing an object variable in the function. For those viewing this that need to do it that way, instead of being able to pass the name of the class as a string, you can do it this way:
class Blah
{
public $x = 123;
}
function Foo($b) {
$class = get_class($b);
$object = new $class();
var_dump($object);
}
$aa = new Blah();
Foo($aa);
I realize this is a bit old but I'll leave an answer anyway just in case it's helpful.
If I am going to pass an object as a parameter to another object, it's going to be after I have instantiated the object argument and adjusted the properties to my needs. The following is an example of how I would go about it. I'm using this on PHP 7.4.x and haven't tested on PHP 8.x yet.
Class Blah is the object that will be passed to an instance of Class Bleep after the property $x within the Class Blah object has been changed from 123 to 456.
<?php
class Blah {
public $x = 123;
function __construct() {}
function set_x($x) {
$this->x = $x;
}
function get_x() {
return $this->x;
}
}
class Bleep {
public $object;
function __construct($object) {
$this->object = $object;
}
function get_object_x() {
return $this->object->get_x();
}
}
// Example in use.
$obj_bla = new Blah();
print '<p>On instantiation of <u>$obj_bla</u> as a <strong>Blah</strong> object, $x = '.$obj_bla->get_x().'</p>';
$obj_bla->set_x(456);
print '<p>After using the method <i>set_x()</i> on <u>$obj_bla</u>, $x = '.$obj_bla->get_x().'</p>';
$obj_bleep = new Bleep($obj_bla);
print '<p>Instantiate <u>$obj_bleep</u> as a new <strong>Bleep</strong> object and pass it the instance of <u>$obj_bla</u> then use the <i>get_object_x()</i> method on <u>$obj_bleep</u> to get the value of x from the object that was passed = '.$obj_bleep->get_object_x().'</p>'
?>

can I create a class dynamically with $? (dollar-sign)

In PHP sometimes it would be nice if I could define a function or a class with a variable name like
$myfunctionname="test";
function $myfunctionname(){
//...
}
so it would create the function test()
or with classes too like:
$foo = bar;
class $foo {
// lots of complicated stuff
// ...
}
but this doesen't work. like this it would give parse errors!
Is there a solution to this?
(I know, this is not good practise, but just as a workaround, it would be handy)
EDIT: My actual problem:
I have a framework with a migration process where every migration step is in a separate php include file in a folder.
Each file contains only one migration class that contains the name of the include file.
Because the class has to have that certain name, I would like to create the name of the class to a generic name that is created by the filename constant __FILE__
Yes, you can, but I dont want you to.
$classname = "test";
eval("class {$classname}{ public function hello(){ echo \"hello!\"; } }");
$evil_class = new $classname();
$evil_class->hello(); // echo's "hello!"
now, if you don't mind me I'm going for a shower.
You can use a factory pattern:
class poly_Factory {
public function __construct() {
$class = 'poly';
return new $class();
}
}
If that is anything you want to get to.
http://net.tutsplus.com/tutorials/php/understanding-and-applying-polymorphism-in-php/
Scroll down to step 4, last part...
I know you did not ask for that, but what can your question be good for else?
No. This code throws a parse error on line 3 because of the $:
$foo = 'bar';
class $foo {
function hello() {
echo "World";
}
}
$mybar = new bar();
$mybar->hello();
Result:
Parse error: syntax error, unexpected T_VARIABLE, expecting T_STRING on line 3
And as Jan Dvorak pointed out in the comments: even if you figure out a way to do this, don't do this.
If you want to create a value object you can just use the stdClass builtin type.
$object = new stdClass;
$object->someValue = "Hello World";
echo $object->someValue;
See it in Action
If you want to assign methods then you have to use the magic __call function, here is how I would do it.
class AnonObject{
private $properties = array();
private $methods = array();
public function __get($property){
return array_key_exists($property, $this->properties)?$this->properties[$property]:null;
}
public function __set($property, $value){
if (!is_string($value) && is_callable($value)){
if ($value instanceof \Closure){
// bind the closure to this object's instance and static context
$this->methods[$property] = $value->bindTo($this,get_class($this));
} else {
// invokable objects
$this->methods[$property] = $value;
}
} else {
$this->properties[$property] = $value;
}
}
public function __call($method, $args){
if (array_key_exists($method, $this->methods)){
call_user_func_array($this->methods[$method], $args);
} else {
throw new RuntimeException("Method ".$method." does not exist on object");
}
}
}
See it In Action
Note, as stated by several other people this is bad practice. If the goal of this exercise is to compose the behavior of an instance of an object at runtime a more maintainable solution would be to use the Strategy Pattern

Echo Return construct method;

<?php
class DBFactory {
function __construct(){
return 'Need to echo';
}
}
$db = new DBFactory;
echo $db;
?>
Not works :(
I dont understand why your looking into OOP if your tryiung to return values on a constructor.
the whole point of OOP is to have objects that perform many tasks, if you want to return a string,array,resource then OOP is not for you.
__constructors are used to initiate code during the pre stages of the object initialization, witch allows you to execute code to prepare an object before the user can use it.
If you wish to use the __toString on objects then use it wisely, its main perpose is for a readability factor in objects, not storage etc. mainly used in error debugging.
When you create an object using the new keyword php's processor creates an object and assigns it to the memory, it then runs the construct but does not hold any returned values from it, after the constructor as reached its endppoint, the link for the object in the memory is returned to the variable you asked it to be. so in theory you can run $db->__construct() as its still a method, but only after the object is fully created.
just create a method to return a string like so
class DBFactory
{
function whatAmI()
{
return 'I am DBFactory';
}
}
$MyOBJECT = new DBFactory;
echo $MyOBJECT->whatAmI();
This is REALLY REALLY Stupid to do but as you wish to know how,
class DBFactory{
function __construct()
{
return 'Need to echo';
}
}
$db = new DBFactory();
echo $db->__construct();
You cannot return anything from the constructor. You're already getting a new object back, you can't get another value on top of that and assign both to $db.
The constructors should not return anything.
If you want to echo an object, you have to define how to form its string representation with the magic method __tostring:
class DBFactory {
function __tostring(){
return 'Need to echo';
}
}
$db = new DBFactory();
echo $db;
Generally it's not possible to return a value in a constructor of a class. In this case, $db contains the instance of the class, not the return value.
You could build a separate function, and have that function return the value:
<?php
class DBFactory {
function toEcho() {
return 'Need to echo';
}
}
$db = new DBFactory();
echo $db->toEcho();
?>
$db = new DBFactory();
i think this "()" also be here
You could use the __toString magic method to get __construct to echo out
or you could just getmetod without using __toString magic method. There are many ways just pick one of them.
<?php
// Declare a simple class
class TestClass
{
public $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
public function __toString()
{
return $this->foo;
}
}
$class = new TestClass('Hello');
echo $class;
?>
__toString()

Call private methods and private properties from outside a class in PHP

I want to access private methods and variables from outside the classes in very rare specific cases.
I've seen that this is not be possible although introspection is used.
The specific case is the next one:
I would like to have something like this:
class Console
{
final public static function run() {
while (TRUE != FALSE) {
echo "\n> ";
$command = trim(fgets(STDIN));
switch ($command) {
case 'exit':
case 'q':
case 'quit':
echo "OK+\n";
return;
default:
ob_start();
eval($command);
$out = ob_get_contents();
ob_end_clean();
print("Command: $command");
print("Output:\n$out");
break;
}
}
}
}
This method should be able to be injected in the code like this:
Class Demo
{
private $a;
final public function myMethod()
{
// some code
Console::run();
// some other code
}
final public function myPublicMethod()
{
return "I can run through eval()";
}
private function myPrivateMethod()
{
return "I cannot run through eval()";
}
}
(this is just one simplification. the real one goes through a socket, and implement a bunch of more things...)
So...
If you instantiate the class Demo and you call $demo->myMethod(), you'll get a console: that console can access the first method writing a command like:
> $this->myPublicMethod();
But you cannot run successfully the second one:
> $this->myPrivateMethod();
Do any of you have any idea, or if there is any library for PHP that allows you to do this?
Thanks a lot!
Just make the method public. But if you want to get tricky you can try this (PHP 5.3):
class LockedGate
{
private function open()
{
return 'how did you get in here?!!';
}
}
$object = new LockedGate();
$reflector = new ReflectionObject($object);
$method = $reflector->getMethod('open');
$method->setAccessible(true);
echo $method->invoke($object);
EDIT:
Updated to include examples of private function calls with parameters.
As of PHP 5.4, you can use the predefined Closure class to bind a method/property of a class to a delta functions that has access even to private members.
The Closure class
For example we have a class with a private variable and we want to access it outside the class:
class Foo {
private $bar = "Foo::Bar";
private function add_ab($a, $b) {
return $a + $b;
}
}
PHP 5.4+
$foo = new Foo;
// Single variable example
$getFooBarCallback = function() {
return $this->bar;
};
$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');
echo $getFooBar(); // Prints Foo::Bar
// Function call with parameters example
$getFooAddABCallback = function() {
// As of PHP 5.6 we can use $this->fn(...func_get_args()) instead of call_user_func_array
return call_user_func_array(array($this, 'add_ab'), func_get_args());
};
$getFooAddAB = $getFooAddABCallback->bindTo($foo, 'Foo');
echo $getFooAddAB(33, 6); // Prints 39
As of PHP 7, you can use the new Closure::call method, to bind any method/property of an obect to a callback function, even for private members:
PHP 7+
$foo = new Foo;
// Single variable example
$getFooBar = function() {
return $this->bar;
};
echo $getFooBar->call($foo); // Prints Foo::Bar
// Function call with parameters example
$getFooAddAB = function() {
return $this->add_ab(...func_get_args());
};
echo $getFooAddAB->call($foo, 33, 6); // Prints 39
The first question you should ask is, if you need to access it from outside the class, why did you declare it private? If it's not your code, the originator probably had a good reason to declare it private, and accessing it directly is a very bad (and largely unmaintainable) practice.
EDIT: As Adam V. points out in the comments, you need to make the private method accessible before invoking it. Code sample updated to include this. I haven't tested it, though - just adding here to keep the answer updated.
That having been said, you can use Reflection to accomplish this. Instantiate ReflectionClass, call getMethod for the method you want to invoke, and then call invoke on the returned ReflectionMethod.
A code sample (though I haven't tested it, so there may be errors) might look like
$demo = new Demo();
$reflection_class = new ReflectionClass("Demo");
$reflection_method = $reflection_class->getMethod("myPrivateMethod");
$reflection_method->setAccessible(true);
$result = $reflection_method->invoke($demo, NULL);
Here's a variation of the other answers that can be used to make such calls one line:
public function callPrivateMethod($object, $methodName)
{
$reflectionClass = new \ReflectionClass($object);
$reflectionMethod = $reflectionClass->getMethod($methodName);
$reflectionMethod->setAccessible(true);
$params = array_slice(func_get_args(), 2); //get all the parameters after $methodName
return $reflectionMethod->invokeArgs($object, $params);
}
I have these problems too sometimes, however I get around it through my coding standards. Private or protected functions are denoted with a prefix underscore ie
private function _myPrivateMethod()
Then i simply make the function public.
public function _myPrivateMethod()
So although the function is public the naming convention gives the notification that whilst public is is private and shouldn't really be used.
If you are able to added a method in the class where the method is defined, you can add method which uses the call_user_method() internally. This works also with PHP 5.2.x
<?php
class SomeClass {
public function callprivate($methodName) {
call_user_method(array($this, $methodName));
}
private function somePrivateMethod() {
echo 'test';
}
}
$object = new SomeClass();
$object->callprivate('somePrivateMethod');
Answer is put public to the method. Whatever trick you are going to do it wouldn't be understandable to fellow developers. For example they do not know that at some other code this function has been accessed as public by looking at the Demo class.
One more thing. that console can access the first method writing a command like:. How can this even be possible? Console can not access demo class functions by using $this.
I guess the reflectionClass is the only alternative if you really want to execute some private methods. Anyhow, if you just need read access to privat or protected properties, you could use this code:
<?php
class Demo
{
private $foo = "bar";
}
$demo = new Demo();
// Will return an object with public, private and protected properties in public scope.
$properties = json_decode(preg_replace('/\\\\u([0-9a-f]{4})|'.get_class($demo).'/i', '', json_encode((array) $demo)));
?>
<?php
$request="email";
$data=[1,2,3,4,5];
$name=new Update($request,$data);
class Update{
private $request;
private $data;
function __construct($request,$data){
$this->request=$request;
$this->data=$data;
if($this->request=='email'){
$this->update_email();
}
else{
echo "Can't do anything";
}
}
private function update_email(){
echo $this->request;
echo '\n';
foreach($this->data as $x){
echo $x."\n";
}
}
}
?>

PHP stdClass() with __get() Magic Method

Take the following code as an example:
class xpto
{
public function __get($key)
{
return $key;
}
}
function xpto()
{
static $instance = null;
if (is_null($instance) === true)
{
$instance = new xpto();
}
return $instance;
}
echo xpto()->haha; // returns "haha"
Now, I'm trying to archive the same result but without have to write the xpto class. My guess is I should have to write something like this:
function xpto()
{
static $instance = null;
if (is_null($instance) === true)
{
$instance = new stdClass();
}
return $instance;
}
echo xpto()->haha; // doesn't work - obviously
Now, is it possible to add __get() magic functionality to the stdClass object? I guess not, but I'm not sure.
No, it is not possible. You cannot add anything to stdClass. Also, unlike Java, where every object is a direct or indirect subclass of Object, this is not the case in PHP.
class A {};
$a = new A();
var_dump($a instanceof stdClass); // will return false
What are you really trying to achieve? Your question sounds a bit like "I want to close the door of my car, but without having a car" :-).
The OP looks like they are trying to achieve a singleton pattern using a function in the global scope which is probably not the correct way to go, but anyway, regarding Cassy's answer, "You cannot add anything to stdClass" - this is not true.
You can add properties to the stdClass simply by assigning a value to them:
$obj = new stdClass();
$obj->myProp = 'Hello Property'; // Adds the public property 'myProp'
echo $obj->myProp;
However, I think you need PHP 5.3+ in order to add methods (anonymous functions / closures), in which case you might be able to do something like the following. However, I've not tried this. But if this does work, can you do the same with the magic __get() method?
UPDATE: As noted in the comments, you cannot dynamically add methods in this way. Assigning an anonymous function (PHP 5.3+) does just that and simply assigns a function (strictly a closure object) to a public property.
$obj = new stdClass();
$obj->myMethod = function($name) {echo 'Hello '.$name;};
// Fatal error: Call to undefined method stdClass::myMethod()
//$obj->myMethod('World');
$m = $obj->myMethod;
$m('World'); // Output: Hello World
call_user_func($obj->myMethod,'Foo'); // Output: Hello Foo

Categories