Instantiating a class with an array as parameters - php

I'm aware of the existence of call_user_func_array, but I don't believe you can use this to construct a class (if you can, how do you do it?). As long as I'm not mistaken, how do you instantiate a class with an array as parameters?
for example:
class Test {
public function __construct($var1, $var2) {
// do something
}
}
how would I instantiate it with this:
array("var1_data", "var2_data")

class Test {
public function __construct(array $params) {
// ...
}
}
Don't use “magic” unless you really need it.
EDIT:
If what you need is varagrs, you can find an answer here.

If you must have multiple constructors, you should name them something other than __construct, then define a __construct method that can accept any number of arguments. Within that method, you can determine which of your custom constructors to use. If all you want to do is allow the constructor to be passed an array instead of a list of arguments, you can do it this way (note that this example lacks any error checking):
public function __construct() {
$args = func_get_args();
if(count($args) == 1 && is_array($args[0])) {
$cArgs = $args[0];
} else {
$cArgs = $args;
}
__do_construct($cArgs[0], $cArgs[1]);
}
private function __do_construct($arg1, $arg2) {
// do something
}

Related

Check call static method php

i have class look like this:
class Foo
{
puclic static function blindPaths($paths)
{
foreach($paths as $name=>$path)
{
$method='set'.ucfirst($name).'Path';
if(method_exists(????,$method))
self::$method($path);
}
}
public function setBasePath($base)
{
//do something...
}
public function setAppPath($app)
{
//do something...
}
....
}
now, i call:
$paths = array(
'base'=>'path.of.base.path',
'app'=>'path.of.app.path',
'someValue'=>'path.of.someValuePath',
....
);
Foo::blindPaths($paths);
problem when check method_exists, what to fill in those marks "????" somebody can help me?
if(method_exists(__CLASS__, $method))
In a simple, single class situation you could use the __CLASS__ constant as a first argument for the method_exists call, but if you're in a situation where the static method is defined at the parent level (or an abstract class, or some place else), then perhaps you may want to consider this:
puclic static function blindPaths($paths)
{
$current = get_called_class();
foreach($paths as $name=>$path)
{
$method='set'.ucfirst($name).'Path';
if(method_exists($current,$method))
self::$method($path);
}
}
Or, if you add interfaces and Trait's to the mix:
puclic static function blindPaths($paths)
{
$current = get_called_class();
$current = new $current;//create instance
foreach($paths as $name=>$path)
{
$method='set'.ucfirst($name).'Path';
if($current instanceof Foo)
self::$method($path);
elseif ($current instanceof Bar)
return $this->{$method}($path);
}
}
But either way, rethink your design. If you're using a construct similar to what you have now, 9 out of 10 times, you're barking up the wrong tree.

can I pass __construct parameters after a class has been instantiated into an object?

I have a similar code snippet like this
class Search
{
public function search($for, $regEx, $flag) //I would like this to be the constructor
{
// logic here
return $this;
}
}
Then I have another class that creates an object from it, later than tries to use the object.
class MyClass
{
public function start()
{
$this->search = new Search();
}
public function load()
{
$this->search($for, $regEx, $flag);
}
}
My question is, is it possible to create an object first THEN give it the parameters?
I know there are some way around this BUT I only ask because I want to use the object like this
$this->search($params);
// I have my methods chained, so I could use it in one line like
// $this->search($params)->hasResults();
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
The way I have it set up right now, I would need to use it like this
$this->search->search($params);
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
I have a method called search() that does the logic, and I don't want to be redundant in my naming nor do I want to change the name of the method.
I know another way to keep the visual appeal sane I could pass a variable like so
$search = $this->search->search($params);
then
$search->hasResults();
At the same time I am trying to introduce myself to new OOP concepts and learn from them. Would this require passing things by reference? or setting up some type of magic method?
While the previous anwsers show that you can, I wouldn't use it, because it breaks the concept of encapsulation. A proper way to achieve what you want is the following
class Search
{
public function __constructor($for='', $regEx='', $flag='')
{
$this->Setup($for, $regEx, $flag);
}
public function Setup($for, $regEx, $flag)
{
//assign params
//clear last result search
//chain
return $this;
}
public function search()
{
// logic here
return $this;
}
}
In this way, you can reuse the object and have the params in the constructor, without breaking encapsulation.
Yes it is possible
See the below example
<?php
class a{
public $a = 5;
public function __construct($var){
$this->a = $var;
}
}
$delta = new a(10);
echo $delta->a."\n";
$delta->__construct(15);
echo $delta->a."\n";
Output will be:
10 15
Yep, you can.
class Example {
public $any;
function __counstruct($parameters,$some_text) {
$this->any=$some_text;
return $this->any;
}
}
You can call constructor:
$obj = new Example (true,'hello');
echo $obj->any;
$obj->__construct(true,'bye-bye');
echo $obj->any;
I was able to create the visual coding I wanted by using the __call() magic method like this
public function __call($name, $params)
{
$call = ucfirst($name);
$this->$name = new $call($params);
}
from there I could use this
$this->test->search($params);
$this->test->search->hasResults();
I of course now set the search() method to the class constructor

Overloading construct in php?

does php (5.3.7) supports overloading ?
Example:
class myclass{
function __construct($arg1) { // Construct with 1 param}
function __construct($arg1,$arg2) { // Construct with 2 param}
}
new myclass(123); //> call the first construct
new myclass(123,'abc'); //> call the second
You have to implement the constructor once and use func_get_args and func_num_args like this:
<?php
class myclass {
function __construct() {
$args = func_get_args();
switch (func_num_args()) {
case 1:
var_dump($args[0]);
break;
case 2:
var_dump($args[0], $args[1]);
break;
default:
throw new Exception("Wrong number of arguments passed to the constructor of myclass");
}
}
}
new myclass(123); //> call the first construct
new myclass(123,'abc'); //> call the second
new myclass(123,'abc','xyz'); //> will throw an exception
This way you can support any number of arguments.
No, but it supports optional parameters, or variable number of parameters.
class myclass{
function __construct($arg1, $arg2 = null){
if($arg2 === null){ // construct with 1 param //}
else{ // construct with 2 param //}
}
}
Note that this has the downside that if you actually want to be able to supply null as a second parameter it will not accept it. But in the remote case you want that you can always use the func_* family of utils.
I would define some fromXXX methods that call the __constructor which takes a parameter like id.
<?php
class MyClass {
public function __construct(int $id) {
$instance = Database::getByID($id);
$this->foo = $instance['foo'];
$this->bar = $instance['bar'];
}
public static function fromFoo(string $foo): MyClass {
$id = Database::find('foo', $foo);
return new MyClass($id);
}
}

PHP[OOP] - How to call class constructor manually?

Please see the code bellow:
01. class Test {
02. public function __construct($param1, $param2, $param3) {
03. echo $param1.$param2.$param3;
04. }
05. }
06.
07. $params = array('p1','p2','p3');
08.
09. $ob = new Test;
10.
11. if(method_exists($ob,'__construct')) {
12. call_user_func_array(array($ob,'__construct'),$params);
13. }
Now, the problem is the constructor is called in line 09
But i want to call it manually at line 11-13
Is it possible? If then how? Any idea please?
It is not possible to prevent the constructor from being called when the object is constructed (line 9 in your code). If there is some functionality that happens in your __construct() method that you wish to postpone until after construction, you should move it to another method. A good name for that method might be init().
Why not just do this?
class Test {
public function __construct($param1, $param2, $param3) {
echo $param1.$param2.$param3;
}
}
$ob = new Test('p1', 'p2', 'p3');
EDIT: I just thought of a hacky way you could prevent a constructor from being called (sort of). You could subclass Test and override the constructor with an empty, do-nothing constructor.
class SubTest extends Test {
public function __construct() {
// don't call parent::__construct()
}
public function init($param1, $param2, $param3) {
parent::__construct($param1, $param2, $param3);
}
}
$ob = new SubTest();
$ob->init('p1', 'p2', 'p3');
This is might make sense if you're dealing with some code that you cannot change for some reason and need to work around some annoying behavior of a poorly written constructor.
Note that if the constructor (__construct method) contains arguments passed by
reference, then the function:
call_user_func_array
will fail with an error.
I suggest you to use Reflection class instead; here is how you can do so:
// assuming that class file is already included.
$refMethod = new ReflectionMethod('class_name_here', '__construct');
$params = $refMethod->getParameters();
$re_args = array();
foreach($params as $key => $param)
{
if ($param->isPassedByReference())
{
$re_args[$key] = &$args[$key];
}
else
{
$re_args[$key] = $args[$key];
}
}
$refClass = new ReflectionClass('class_name_here');
$class_instance = $refClass->newInstanceArgs((array) $re_args);
I don't know if there are some security concerns by using the eval() method, but you could make yourself a function like this:
function CreateObj($className,$params)
{
$strArgs = '$params['.implode('],$params[',array_keys($params)).']';
eval('$ob = new '.$className.'('.$strArgs.');');
return $ob
}
And now $ob should now be defined with its correct parameters, i haven't tested it and maybe there is a mistake in the code, but you get the idea....
If separating instantiation from initialization isn't strictly a requirement, there are two other possibilities: first, a static factory method.
class Test {
public function __construct($param1, $param2, $param3) {
echo $param1.$param2.$param3;
}
public static function CreateTest($param1, $param2, $param3) {
return new Test($param1, $param2, $param3);
}
}
$params = array('p1','p2','p3');
if(method_exists($ob,'__construct')) {
call_user_func_array(array($ob,'CreateTest'),$params);
}
Or, if you're using php 5.3.0 or higher, you can use a lambda:
class Test {
public function __construct($param1, $param2, $param3) {
echo $param1.$param2.$param3;
}
}
$params = array('p1','p2','p3');
$func = function ($arg1, $arg2, $arg3) {
return new Test($arg1, $arg2, $arg3);
}
if(method_exists($ob,'__construct')) {
call_user_func_array($func, $params);
}
The initialization method described by Asaph is great if for some reason you have a need to logically separate initialization from instantiation, but if supporting your use case above is a special case, not a regular requirement, it can be inconvenient to require users to instantiate and initialize your object in two separate steps.
The factory method is nice because it gives you a method to call to get an initialized instance. The object is initialized and instantiated in the same operation, though, so if you have a need to separate the two it won't work.
And lastly, I recommend the lambda if this initialization mechanism is uncommonly used, and you don't want to clutter your class definition with initialization or factory methods that will hardly ever be used.
In PHP you can create objects w/o calling the constructor. But that does not work by using new but by un-serializing an object instance.
The constructor can then be called manually.
Normally this is not needed. See as well: Loading an object from PHP session, does it call constructor?
<?php
class Test
{
public function __construct()
{
echo '__construct called.',"\n";
}
}
function old($class)
{
return unserialize
(
sprintf
(
'O:%d:"%s":0:{}',
strlen($class),
$class
)
);
}
$test = old('Test');
$test->__construct();
to construct your object first and then pass parameters your could try this way:
class Test {
public function __CONSTRUCT($p1="Bundy", $p2="house", $p3=10) {
$this->init($p1, $p2, $p3);
}
public function init($p1, $p2, $p3) {
//setup your object here
}
}
then it is possible to construct the object and call
$ob->init($p1, $p2, $p3);
later.
I see no reason why the constructor should be deferred so this below still achieves what you probably want and even better because the constructor will by default be called on object instantiation.
class Test {
public function __construct()
{
}
public function init($param1, $param2, $param3){
echo $param1.$param2.$param3;
}
}
$params = array('p1','p2','p3');
$ob = new Test();
if(method_exists($ob,'init')) {
call_user_func_array(array($ob,'init'),$params);
}

Calling a changing function name on an object with PHP : how?

How would I do something like this :
class Test
{
public function test($methodName) {
$this->$methodName;
}
private function a() {
echo("a");
}
private function b() {
echo("b");
}
}
$testObj = new Test();
$testObj->test("a()");
$testObj->test("b()");
Maybe I should just pass a parameter "TYPE" and use a "IF statement" but I'm just curious! :)
And what if the "dynamic function name" has one or more parameters?
UPDATE : Thanks everyone! :)
UPDATE #2 - Answer :
class Test
{
public function testOut($methodName) {
$this->$methodName();
}
private function a() {
echo("a");
}
private function b() {
echo("b");
}
}
$testObj = new Test();
$testObj->testOut("a");
$testObj->testOut("b");
The problem with the class is that there was a method named "Test" (the same as the class name)... I changed it and it worked.
class Test
{
public function test($methodName) {
$this->$methodName();
}
private function a() {
echo("a");
}
private function b() {
echo("b");
}
}
$testObj = new Test();
$testObj->test("a");
$testObj->test("b");
Check out call_user_func() - it should do what you want.
Documentation here
call_user_func allows you to do things like this.
For example,
funcname = 'a';
call_user_func(array($testObj, $funcname));
The other alternative is to use variable methods
For example,
$funcname = 'a';
$testObj->$funcname();
If you have a "dynamic function name" with more than one parameter, you can use call_user_func_array, like this:
//in class context..
//$parameters can be an array like array(1,2)
call_user_func_array(array($this, $methodName), $parameters);
The reason you would want to use call_user_func_array instead of call_user_func is that you can pass the parameters the function takes as an array, instead of just as additional parameters, thus allowing you to easily have a variable number of arguments.
Following your particular example and use case, the only way to achieve this exactly:
$testObj = new Test();
$testObj->test("a()");
$testObj->test("b()");
would be to use eval():
class Test
{
public function test($methodName) {
eval($methodName);
}
private function a() {
echo("a");
}
private function b() {
echo("b");
}
}
$testObj = new Test();
$testObj->test("a()");
$testObj->test("b()");
Others pointed out a solution using call_user_func() and rightly so. Also evidently, is faster than using eval() for function calls. Read this:
http://nz.php.net/manual/en/function.call-user-func.php#64415

Categories