How can I mention keyword arguments in php constructor? - php

I am new to PHP OOP.
I have this constructor
protected $path='default';
function __construct($var1, $var2 ..){
$this->var1=$var1;
$this->var2=$var2;
}
$obj = MyClass($var1='www')
I want that if I make object and don't pass any arguments then I get the object with empty values.
But if mention the properties in the constructor like above then the object should have those properties set.
Currently if I define the constructor with args and don't supply any then I get error
.

You could make use func_get_args() in PHP
<?php
class foo
{
private $arrParams;
function __construct()
{
if (func_num_args() != 0) {
$this->arrParams = $this->setValues(func_get_args());
}
}
public function setValues($params)
{
return $params;
}
public function dispParams()
{
print_r($this->arrParams);
}
public function retVal($var)
{
return $this->arrParams[$var];
}
}
$foo1 = new Foo(3, 45, 64, 34);
$foo1->dispParams();
OUTPUT :
Array
(
[0] => 3
[1] => 45
[2] => 64
[3] => 34
)
For getting a corresponding value from the array... You could just call
$foo1->retVal(2); // Prints you 64

you need to declare class property like this:
class yourClass{
protected $path='default';
public $var1;
public $var2;
function __construct($var1="dd", $var2='ss'){
$this->var1=$var1;
$this->var2=$var2;
}
}
$obj = new yourClass();
echo "without params: ".$obj->var1.$obj->var2;
$obj2 = new yourClass("sdf","sfdsdf");
echo " with params : ".$obj2->var1.$obj2->var2;
Demo

Related

PHP stacking classes returns nothing

I'm creating a small, multiclass system that extends each other. Lets say class a is a "core" and work as a checking/administration wrapper. class b is to check what $d is and call a method of class c, a user class, if it exists or trigger an error to class a back.
Here's my code:
<?php
class a {
private $error;
private $ok;
public function __construct() {
$this->error = array();
$this->ok = array();
// do other stuff here
}
}
class b extends a {
private $head;
private $out;
public function __construct() {
parent::__construct();
global $d;
$this->head = "";
$this->out = "";
if(method_exists($this,$d)) {
$this->{$d}();
} else
$this->error[] = "method '$d' not found";
}
public function output() {
return ($this->head==""?"":'<h1>'.$this->head.'</h1>').$this->out;
}
}
class c extends b {
private $me = "inside c";
public function standard() {
$this->head = "Heading";
$this->out = "it works!";
}
}
$d = "standard";
$c = new c();
echo "<pre>".print_r($c,true)."</pre>";
echo $c->output();
?>
if i ran $c->output() it returns nothing, but the print_r() returns this:
c Object
(
[me:c:private] => inside c
[head:b:private] =>
[out:b:private] =>
[error:a:private] => Array
(
)
[ok:a:private] => Array
(
)
[head] => Heading
[out] => it works!
)
Could anyone please help me with this?
It's because you've declared all your class variables as private. This makes it so that only the class where they were declared can access them. Not even subclasses (derived classes) can see them.
If you need subclasses to access the variables of a parent class, you should declare them as protected.
http://php.net/manual/en/language.oop5.visibility.php
You should use protected instead of private!
Try
protected $head;
protected $out;

Print_R of class as array

I have a class, that actually operates over a complicated array to make the manipulation more simple. The format of original array looks like this:
array(
array(
"name" =>"foo",
"type" =>8, //The array is NBT format and 8 stands for string
"value" =>"somevalue"
)
}
The class takes array like above as constructor:
class NBT_traverser implements ArrayAccess {
function __construct(&$array) {
$this->array = $array;
}
}
Then, this is how the members are accessed:
$parser = new NBT_traverser($somearray);
echo $parser["foo"]; //"somevalue"
When I print_R the class, I get the list of its values and the original complicated array. Like this:
object(NBT_traverser)#2 (1) {
["nbt":"NBT_traverser":private]=> &array(1) {
/*Tons of ugly array contents*/
}
Instead, I'd like to get this like the output of print_r:
array(
"foo" => "somevalue"
)
Is it possible to trick the print_r to do this? Current behavior makes it harder to debug with the class, than without it.
Of course, I can write my own method to print it, but I want to make the usage more simple for the users of the class. Instead, I wanted to give print_R something, that It will print as array.
You should not have issues if you are extending ArrayAccess just write a method to get your values
Example
$random = range("A", "F");
$array = array_combine($random, $random);
$parser = new NBT_traverser($array);
echo $parser->getPrint();
Output
Array
(
[A] => A
[B] => B
[C] => C
[D] => D
[E] => E
[F] => F
)
Class Used
class NBT_traverser implements ArrayAccess {
private $used; // you don't want this
protected $ugly = array(); // you don't want this
public $error = 0202; // you don't want this
private $array = array(); // you want this
function __construct(&$array) {
$this->array = $array;
}
function getPrint() {
return print_r($this->array, true);
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->array[] = $value;
} else {
$this->array[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->array[$offset]);
}
public function offsetUnset($offset) {
unset($this->array[$offset]);
}
public function offsetGet($offset) {
return isset($this->array[$offset]) ? $this->array[$offset] : null;
}
}
You could use the __toString function in your class
class Test
{
private $_array = array();
public function __toString()
{
return print_r($this->_array, true);
}
}
And then just echo out your class
$test = new Test();
echo $test;
I think this would print out your array as you want it to be?
Array
(
)

__get and __set not behaving as expected

<?php
class BaseClass {
protected $data = array("foo" => 0, "bar" => 0, "baz" => 0);
public function __set($name, $value) {
if( array_key_exists($name, $this->data)){
$func = "set_$name";
return call_user_func_array(array($this,$func),array($value));
}
}
public function __get($name) {
if ( array_key_exists($name, $this->data)){
$func = "get_$name";
return call_user_func_array(array($this,$func),array());
}
}
public function __call($method, $args) {
if (method_exists($this,$method)) {
return call_user_func_array(array($this,$method),$args);
}
if (substr($method, 0, 4) == 'set_'){
$var_name = substr($method, 4);
if (!(array_key_exists($var_name, $this->data))){
return FALSE;
}
$this->data[$var_name] = $args[0];
return TRUE;
}
if (substr($method, 0, 4) == 'get_'){
$var_name = substr($method, 4);
if (!(array_key_exists($var_name, $this->data))){
return FALSE;
}
return $this->data[$var_name];
}
}
}
class SubClass extends BaseClass {
protected $baz_changed = FALSE;
public function set_baz($value) {
if ($value != $this->baz){
print "\n\nthis->data BEFORE SET: ";
print_r($this->data);
print "\n\nthis->baz: ";
print_r($this->baz);
print "\n\nPASSED baz: ";
print_r($value);
$this->baz = $value;
print "\n\nbaz AFTER SET: ";
print_r($this->baz); // appears it was set
print "\n\nDATA ARRAY: ";
print_r($this->data); // but it wasn't ... what gives?
$this->baz_changed = TRUE;
}
}
}
$sc = new SubClass();
$sc->foo = 1;
print "\n\$sc->foo = $sc->foo\n";
$sc->baz = 5;
print "\$sc->baz = $sc->baz\n";
?>
I get the following results are not as I would have expected:
$sc->foo = 1
this->data BEFORE SET: Array (
[foo] => 1
[bar] => 0
[baz] => 0 )
this->baz: 0
PASSED baz: 5
baz AFTER SET: 5
DATA ARRAY: Array (
[foo] => 1
[bar] => 0
[baz] => 0 ) $sc->baz = 5
As you can see, it appears that baz is set but it never gets set in the data array. Can anyone explain why and how to fix this?
EDIT: Fixed formatting of the results and adding more context to this code section because stackoverflow is complaining I do not have enough.
EDIT: Just noticed that at the end it says $sc->baz = 5. But the data array isn't updated. This is not expected I would rather that the data array version of baz were updated. Instead of a new instance variable created in SubClass.
You're attempting to recursively call __set, and PHP specifically disallows this.
In __set, you call set_baz
In set_baz, you do $this->baz = 5
This would invoke __set, except PHP prevents this from happening. If it didn't, your program would never end.
You cannot trigger __set if you're already within __set. Instead, you are dynamically defining a new member variable called $this->baz exactly as if __set did not exist. If you var_dump your object, you will find that it now contains both $data and $baz members.
Inside set_baz, you need to explicitly write to $this->data. You cannot write to $this->baz.
It's behaving correctly, when you do $sc->baz = 5; it finds that set_baz method is there and executes this line $this->baz = $value; and sets the value of baz property
Assume if the __get and __set working on in the class too then how you access $this->data in the class?

Make my own (non-database) fetch_object function

In php mysql / mysqli / postgre / etc... there are fetch_object functions where you can get an object for your row of data. By default it will return an object of stdClass, but you can also define a class_name and an array of params for the constructor.
I would like to do the same thing with a plain set of values. Preferably, setting the properties of the object before calling the constructor, which is the same behaviour the database-functions show. However, this doesn't seem to be possible.
The only way to even create an object with properties set seems to be to unserialize a preconstructed string. But that example still creates a new object as well, then sets the properties of that object from the unserialized object to ensure the constructor is called. But this means the constructor is called before the properties are set.
In short: I would like the following:
array_fetch_object(array $properties, string $class_name [, array $params ])
with the constructor called after the properties are set.
In the end I wrote the following class which performs the task using unserializing a fabricated string. It uses reflection to determine what the access-type of properties is and what the name of the constructor is (if any).
The heart of the class is the following line:
$object = unserialize('O:'.strlen($class_name).':"'.$class_name.'"'.substr(serialize($properties), 1));
which serializes the property-array and renames the serialized to the desired class_name.
class ObjectFactory {
private $properties;
private $constructors;
public function __construct() {
$this->properties = array();
$this->constructors = array();
}
private function setClass($class_name) {
$class = new ReflectionClass($class_name);
$this->properties[$class_name] = array();
foreach($class->getProperties() as $property) {
$name = $property->getName();
$modifier = $property->getModifiers();
if($modifier & ReflectionProperty::IS_STATIC) {
continue;
} else if($modifier & ReflectionProperty::IS_PUBLIC) {
$this->properties[$class_name][$name] = $name;
} else if($modifier & ReflectionProperty::IS_PROTECTED) {
$this->properties[$class_name][$name] = "\0*\0".$name; // prefix * with \0's unserializes to protected property
} else if($modifier & ReflectionProperty::IS_PRIVATE) {
$this->properties[$class_name][$name] = "\0".$class_name."\0".$name; // prefix class_name with \0's unserializes to private property
}
}
if($constructor = $class->getConstructor()) {
$this->constructors[$class_name] = $constructor->getName();
}
}
private function hasClassSet($class_name) {
return array_key_exists($class_name, $this->properties);
}
private function hasClassProperty($class_name, $property_name) {
if(!$this->hasClassSet($class_name))
$this->setClass($class_name);
return array_key_exists($property_name, $this->properties[$class_name]);
}
private function getClassProperty($class_name, $property_name) {
if(!$this->hasClassProperty($class_name, $property_name))
return false;
return $this->properties[$class_name][$property_name];
}
private function hasClassConstructor($class_name) {
if(!$this->hasClassSet($class_name))
$this->setClass($class_name);
return $this->constructors[$class_name] !== false;
}
private function getClassConstructor($class_name) {
if(!$this->hasClassConstructor($class_name))
return false;
return $this->constructors[$class_name];
}
public function fetch_object(array $assoc, $class_name = 'stdClass', array $params = array()) {
$properties = array();
foreach($assoc as $key => $value) {
if($property = $this->getClassProperty($class_name, $key)) {
$properties[$property] = $value;
}
}
$object = unserialize('O:'.strlen($class_name).':"'.$class_name.'"'.substr(serialize($properties), 1));
if($constructor = $this->getClassConstructor($class_name)) {
call_user_func_array(array($object, $constructor), $params);
}
return $object;
}
}
Well, you can cast an array to an object, like this:
$array = array('a' => 'a', 'b' => 'c');
$object = (object) $array;
or just:
$object = (object) array('a' => 'a', 'b' => 'c');
This will give you a stdClass object with the properties of the array.
Ok, I didn't expect this to work, but it does:
class TestObject {
public $property;
public $preset;
public function __construct($param) {
$this->property = $param;
}
}
$object = unserialize('O:10:"TestObject":1:{s:6:"preset";i:1;}');
$object->__construct(1);
print_r($object);
results:
TestObject Object
(
[property] => 1
[preset] => 1
)
I just have to check the access type of the property before creating the serialized string because the classname is prepended for private properties. However, is calling the constructor of an already constructed object expected to stay working?

How to call the construct of a ReflectionObject and how to get this from a ReflectionClass

I have an array of reflectionClasses.
I need to get a reflectionObject from one of these and then call its constructor with some parameters.
The point is to instantiate an object without knowing the class name (i'll know it at runtime).
Example, just to render the idea:
foreach (Conf::get_array() as $reflection_class) {
//it's not right, just to render the idea
$reflectionObject = new ReflectionObject ($reflection_class);
$objects[] = $reflectionObject->construct($param_1, $param_2);
}
Another example:
foreach (Conf::get_array() as $reflection_class) {
$objects[] = new $reflection_class($param_1, $param_2); //not right. maybe from php 5.3?
}
You don't need an instance of ReflectionObject for that. ReflectionClass has the two methods
public stdclass newInstance(mixed args)
public stdclass newInstanceArgs(array args)
example:
<?php
class Foo {
public function __construct($a, $b) { echo "Foo($a,$b) "; }
}
class Bar {
public function __construct($a, $b) { echo "Bar($a,$b) "; }
}
class Conf {
public static function get_array() {
return array(new ReflectionClass('Foo'), new ReflectionClass('Bar'));
}
}
$args = array('A', 'B');
$object = array();
foreach (Conf::get_array() as $reflection_class) {
$objects[] = $reflection_class->newInstanceArgs($args);
}
var_dump($objects);

Categories