Lets say I have a class that is responsible for composing another class:
class ClassBuilder
{
protected $baseClass;
public function __construct()
{
$this->baseClass = new BaseClass();
}
public function set()
{
$this->baseClass->foo = 'bar';
}
// other methods to further modify BaseClass
}
class BaseClass
{
public $foo;
}
class ChildClass extends BaseClass {}
I want to create a method in the ClassBuilder that would allow me to update its baseClass property to an instance of ChildClass with the same property values as the current BaseClass object. How can I do that?
public function update()
{
// $this->baseClass = new ChildClass() with the current property values in BaseClass
}
I'm not sure that your overall approach is correct, but about the only way is to loop and set:
public function update()
{
$new = new ChildClass();
foreach($this->baseClass as $name => $value) {
$new->$name = $value;
}
$this->baseClass = $new;
//or
$this->baseClass = clone $new;
}
Related
I am testing a class in phpunit, but I am not mocking it, the class is like that:
class MyClass extends ParentClass
{
public function doSomething($param)
{
//do some stuff
$someValue = $this->anotherMethod(); //this method is defined in the parent class
//do some other stuff with $someValue
return $finalValue;
}
}
in the test class I am doing like this
public function testDoSomething($param)
{
$myclass = new MyClass();
//here I need to control the value of $someValue, as it affects the final value returned
$res = $myClass->doSomething();
$this->assertEqual('sonething', res);
}
so my question is How can I control the value returned from anotherMethod method? I'd prefer to mock it so it does not call other methods in it
You could partially mock your class and instrument the methods that you do not want to test, as the following example:
public function testDoSomething()
{
/** #var \App\Models\MyClass $classUnderTest */
$classUnderTest = $this->getMockBuilder(\App\Models\MyClass::class)
->onlyMethods(['anotherMethod'])
->getMock();
$classUnderTest->expects($this->once())
->method('anotherMethod')
->willReturn('mocked-value');
$this->assertEquals("from-test mocked-value", $classUnderTest->doSomething("from-test"));
}
with the following sources:
ParentClass
class ParentClass
{
public function anotherMethod() {
return "parent-value";
}
}
and MyClass
class MyClass extends ParentClass
{
public function doSomething($param)
{
//do some stuff
$someValue = $this->anotherMethod(); //this method is defined in the parent class
//do some other stuff with $someValue
$finalValue = $param . ' '. $someValue;
return $finalValue;
}
}
I am trying to execute initialize() method for each class that extends from a baseClass, by using late static bindings:
class BaseClass
{
protected static $initialized = false;
public static function find()
{
static::initialize();
//TODO search entries and return as instances...
}
protected static function initialize()
{
if (static::$initialized)
return;
echo 'Initializing ', static::class, '<br/>';
//do important stuff
static::$initialized = true;
}
}
class Child1 extends BaseClass {}
class Child2 extends BaseClass {}
$initialized property is being shared across the extending classes.
Child1::find(); //Outputs 'Initializing Child1', as expected
Child2::find(); //Doesn't execute 'initialize()' because
//$initialized property was set to true by Child1
//Expected: 'Initializing Child2'
Is there a simple way to achieve it?
You can change $initialized to an array (as suggested in comment) using class names as keys:
class BaseClass
{
protected static $initialized = [];
public static function find()
{
return static::initialize();
}
protected static function initialize()
{
$class_name = static::class;
if (!empty(static::$initialized[$class_name])) {
return static::$initialized[$class_name];
}
echo 'Initializing ', $class_name, '<br/>';
//do important stuff
static::$initialized[$class_name] = new static();
// do another important stuff and return instance
return static::$initialized[$class_name];
}
}
class Child1 extends BaseClass {}
class Child2 extends BaseClass {}
Is there any way I can write my code something like this:
<?php
class BaseClass {
public $testvar;
public function __construct ($testvar) {
$this->testvar = $testvar;
}
}
class ChildClass1 extends BaseClass {
}
class ChildClass2 extends BaseClass {
}
$bc = new BaseClass('test1');
$cc1 = new ChildClass1();
$bc->testvar = 'test2';
$cc2 = new ChildClass2();
echo $cc1->testvar; // should echo 'test1'
echo $cc2->testvar; // should echo 'test2'
?>
The reason I am asking is so that I don't have to specify the parameters every time I create a new child class. I want to make it so I only have to specify the parameters once (preferably when creating the base class).
Is this possible?
It's the point of object oriented programming that every instance has it's own parameters.
But sometimes you just want to use a class once for the whole application. Like a database controller or a router. You can then use static properties and methods:
class BaseClass {
public static $testvar;
public function __construct ($testvar) {
self::$testvar = $testvar;
}
}
Note that the value of the static $testvar is the same in all objects. You could work around that with something like this:"
class BaseClass {
public $testvar;
public static $test_var;
public function __construct ($testvar = '') {
if (!empty($testvar)) {
self::$test_var = $testvar;
}
$this->testvar = self::$test_var;
}
}
class ChildClass1 extends BaseClass {
}
class ChildClass2 extends BaseClass {
}
$bc = new BaseClass('test1');
$cc1 = new ChildClass1();
echo $cc1->testvar; // should echo 'test1'
BaseClass::$test_var = 'test2';
$cc2 = new ChildClass2();
echo $cc1->testvar; // **should echo 'test1'**
echo $cc2->testvar; // should echo 'test2'
I have tried in yii frame work adding set function in CController and try to add property in controller's object but it gives error
Can i user base class's __set function to set property of a instance.
Class Base {
public function __set() {
$this->$name = $value;
}
}
Class SubClass1 extends Base{
}
Class SubClass2 extends Base {
}
I create instance of SubClass1 or SubClass2 and i want to add property dynamically. Is it possible.
yes you can unless the property is private
Yes you can place your magic function your your class structure. Magic functions normally calls even if you are not defining in class file.
So, if you not create __set() in your class file, it won't affect much. But, if you want to do some extra things while setting under object then it will be helpful.
Also, __set() function need two parameter, $name and $value. Please refer following url,
__set() magic function
Regards
You can indeed, the following will demonstrate:
<?php
class Foo
{
private $vars = array();
public function __set($name, $value)
{
echo "Setting $name: $value<br />";
$this->vars[$name] = $value;
}
public function __get($name)
{
echo "Getting $name<br />";
return isset($this->vars[$name]) ? $this->vars[$name] : null;
}
}
class Bar extends Foo {}
$bar = new Bar();
$bar->baz = 'baz';
echo $bar->baz;
Which will output:
Setting baz: baz
Getting baz
baz
class Base {
protected $data;
public function __construct() {
$this->someMethodBaseClass();
}
protected function someMethodBaseClass() {
$this->data = 123456;
}
}
class subclass1 extends Base{
public function __construct() {
parent::__construct();
}
public function getData() {
return $this->data;
}
}
is it possible to easily and quickly "assigning properties of one object to another"
class a {
public $number_one;
public $number_two;
public $number_three;
function __contruct() {
//do stuff
}
}
class b {
public $my_var;
function __contruct() {
$instanc_a = new a();
extract( $instance ); // but make these extracted object properties of class b????
// how? :-(
echo $this->number_one;
}
}
You can use get_object_vars to copy the public (only) properties of class a to the current object:
class b {
public $my_var;
function __construct() {
$instanc_a = new a();
$vars = get_object_vars($instanc_a);
foreach($vars as $name => $value) {
$this->$name = $value;
}
echo $this->number_one;
}
}
See it in action.
Note: You have a typo in your code (two cases of "contruct" instead of "construct") which will prevent things from working as they should.
Sounds like you actually want class b to extend class a
class b extends a {
public $my_var;
function __construct () {
parent::__construct();
// Now $this refers to anything in class b, or if it doesn't exist here, looks to class a for it
echo $this->number_one;
}
}