HI!
basicly what I ask u to tell me is how to put a "parent" reference into the object
I need it to make example of "extracting method with method object" - one of mostly used refactoring in Java or C#
in Java refering to "parent object" looks like this:
class someClass {
MyObject myObj = new MyObject(this);
}
and thats it :)
but I dont know, how to do the same in PHP
maybe if its imposible you would tell me how you extract your methods out of your classes to new class, that has to do what that method did.
so in other words...
1 - I have class with big and hard to read / refactor method.
2 - I extract that method to new class, giving it fields in place of parameters and method like "execute" - to proced all that this class has to do for me.
3 - I put object of my class to my old function class and I call its method "execute" - so the all logic that was in my_big_method is done.
The best method is inheritance, where you call the parent keyword to access the parent class like so:
class Child extends Father
{
public function __construct()
{
parent::__construct();
}
}
class Father
{
public function __construct()
{
echo "Father says hello";
}
}
new Child();
using the parent keyowrd you can call the constructor like so parent::__construct()
Example: http://codepad.org/kW6dfVMs
if your looking at Injection then you could do something like this.
class Master
{
private $Slave;
public function __construct(Slave $Slave)
{
$this->Slave = $Slave;
}
}
$Master = new Master(new Slave);
if your unsure of the object that should be passed in but you know that it should have a certain interface / set of methods you can get a little more complex and do something like so:
class Master
{
private $Slave;
public function __construct(ISlave $Slave)
{
$this->Slave = $Slave;
}
}
interface ISlave
{
//Declaration of methods
}
class SomeSlaveObject implements ISlave{}
$Master = new Master(new SomeSlaveObject);
Have you tried using the $this keyword?
Easiest way is to pass a reference to the parent object in the constructor, though I may be misunderstanding your goal.
class myClass {
private $parent = false;
function __construct ($parent=false) {
$this->parent = $parent;
}
}
If you are extending a base class, you can use the parent operator:
class otherClass {
function someMethod() {
return 1;
}
}
class myClass extends otherClass {
function aMethod() {
// parent keyword here would refer to "otherClass"
return $this->someMethod();
}
}
Check out the doc on parent: http://php.net/manual/en/keyword.parent.php
PHP version of your example:
class someClass {
public function createObject() {
$myObj = new MyObject($this);
}
}
not much different than java, just less types and more $ signs.
"parent" is a keyword in php, like the java "super" so your question is a little confusing.
I tried with "$this", but "php guy" in my company told me that I cant use $this that is not refering to field or function of current class (that it cant refer to whole class)
my code looks like this:
class to refactor:
class AccountBeforeRefactoring {
// (...)
public function makeTransfer($amount, $destinationAccount){
$transferFee = 1;
if ($amount > 1000){
$transferFee = 1 + $amount * 0.0001;
}
$this->connectToElixir();
// (...)
// (...)
// (...)
$this->debit($amount + $transferFee);
}
}
and it becomes:
class extracted - that was my method:
class TransferMaker {
private $account;
private $amount;
private $destinationAccount;
private $transferFee;
public function __construct($source, $amount, $destinationAccount){
$this->account = $source;
$this->amount = $amount;
$this->destinationAccount = $destinationAccount;
$this->transferFee = 1;
}
public function make(){
if ($this->amount > 1000){
$this->transferFee = 1 + $this->amount * 0.0001;
}
$this->account->connectToElixir();
// (...)
// (...)
// (...)
$this->account->debit($this->amount + $this->transferFee);
}
}
is constructor there made in right way?
and now I need, to make object of MakeTransfer inside my Account class - I tried it this way - is it ok?
class Account {
// (...)
public function makeTransfer($amount, $destinationAccount){
new TransferMaker($this, $amount,
$destinationAccount).make();
}
}
and again - can I just this "$this" just like this? ;)
will my code work? it does compile in Eclipse, but that can mean none.
Related
I have two classes: Action and MyAction. The latter is declared as:
class MyAction extends Action {/* some methods here */}
All I need is method in the Action class (only in it, because there will be a lot of inherited classes, and I don’t want to implement this method in all of them), which will return classname from a static call. Here is what I’m talking about:
Class Action {
function n(){/* something */}
}
And when I call it:
MyAction::n(); // it should return "MyAction"
But each declaration in the parent class has access only to the parent class __CLASS__ variable, which has the value “Action”.
Is there any possible way to do this?
__CLASS__ always returns the name of the class in which it was used, so it's not much help with a static method. If the method wasn't static you could simply use get_class($this). e.g.
class Action {
public function n(){
echo get_class($this);
}
}
class MyAction extends Action {
}
$foo=new MyAction;
$foo->n(); //displays 'MyAction'
Late static bindings, available in PHP 5.3+
Now that PHP 5.3 is released, you can use late static bindings, which let you resolve the target class for a static method call at runtime rather than when it is defined.
While the feature does not introduce a new magic constant to tell you the classname you were called through, it does provide a new function, get_called_class() which can tell you the name of the class a static method was called in. Here's an example:
Class Action {
public static function n() {
return get_called_class();
}
}
class MyAction extends Action {
}
echo MyAction::n(); //displays MyAction
Since 5.5 you can use class keyword for the class name resolution, which would be a lot faster than making function calls. Also works with interfaces.
// C extends B extends A
static::class // MyNamespace\ClassC when run in A
self::class // MyNamespace\ClassA when run in A
parent::class // MyNamespace\ClassB when run in C
MyClass::class // MyNamespace\MyClass
It's not the ideal solution, but it works on PHP < 5.3.0.
The code was copied from septuro.com
if(!function_exists('get_called_class')) {
class class_tools {
static $i = 0;
static $fl = null;
static function get_called_class() {
$bt = debug_backtrace();
if (self::$fl == $bt[2]['file'].$bt[2]['line']) {
self::$i++;
} else {
self::$i = 0;
self::$fl = $bt[2]['file'].$bt[2]['line'];
}
$lines = file($bt[2]['file']);
preg_match_all('/([a-zA-Z0-9\_]+)::'.$bt[2]['function'].'/',
$lines[$bt[2]['line']-1],
$matches);
return $matches[1][self::$i];
}
}
function get_called_class() {
return class_tools::get_called_class();
}
}
Now (when 5.3 has arrived) it's pretty simple:
http://php.net/manual/en/function.get-called-class.php
class MainSingleton {
private static $instances = array();
private static function get_called_class() {
$t = debug_backtrace();
return $t[count($t)-1]["class"];
}
public static function getInstance() {
$class = self::get_called_class();
if(!isset(self::$instances[$class]) ) {
self::$instances[$class] = new $class;
}
return self::$instances[$class];
}
}
class Singleton extends MainSingleton {
public static function getInstance()
{
return parent::getInstance();
}
protected function __construct() {
echo "A". PHP_EOL;
}
protected function __clone() {}
public function test() {
echo " * test called * ";
}
}
Singleton::getInstance()->test();
Singleton::getInstance()->test();
(PHP 5 >= 5.3.0, PHP 7)
get_called_class — The "Late Static Binding" class name
<?php
class Model
{
public static function find()
{
return get_called_class();
}
}
class User extends Model
{
}
echo User::find();
this link might be helpfull
There is no way, in the available PHP versions, to do what you want. Paul Dixon's solution is the only one. I mean, the code example, as the late static bindings feature he's talking about is available as of PHP 5.3, which is in beta.
I'm a bit confused on whether or not this is possible. I've checked a couple of posts here on SO and they don't really explain what I'm looking for.
I have 3 classes. One main class and two classes extending that main class. (see code below). Is it possible to run a method in one of the two extended classes from it's sibling (the other extended class)?
If it's not possible, how can I change my code to accomplish what I'm doing in the example below?
DECLARATION
class A {
public function __construct() {
//do stuff
}
}
class B extends A {
private $classb = array();
public function __construct() {
parent::__construct();
//do stuff
}
public function get($i) {
return $this->classb[$i];
}
public function set($i, $v) {
$this->classb[$i] = $v;
}
}
class C extends A {
public function __construct() {
parent::__construct();
//do stuff
}
public function display_stuff($i) {
echo $this->get($i); //doesn't work
echo parent::get($i); //doesn't work
}
}
USAGE
$b = new B();
$c = new C();
$b->set('stuff', 'somestufftodisplay');
$c->display_stuff('stuff'); // <----- Displays nothing.
Your code shows an additional problem apart from the main question so there are really two answers:
No, you cannot run a method from a sibling class in another sibling class. If you need that, the method should be in the parent class. The same applies to properties.
You cannot use the value of a property from one object in another object, even if they are both of the same class. Setting a property value in one object sets its value only there as different objects can have the same properties with completely different values. If you need to share the value of a property between the objects and also be able to modify it, you should use a static property. In this case you would have to define that in the parent class, see my previous point.
So to make it work, you would need something like
class A {
private static $var = array();
public function get($i) {
return self::$var[$i];
}
public function set($i, $v) {
self::$var[$i] = $v;
}
}
class B extends A {
}
class C extends A {
public function display_stuff($i) {
echo $this->get($i); // works!
}
}
$b = new B();
$c = new C();
$b->set('stuff', 'somestufftodisplay');
$c->display_stuff('stuff');
An example.
I am using PHP.
As properties defined within the core of a class must be static, I have to create one property in the constructor to allow me to create it with a dynamic name.
Example
final class User extends Z
{
}
Abstract Class Z
{
function __constructor()
{
$x = get_called_class() . 'Id';
$this->$x = null;
}
}
If we var_dump() obj User we would have
object(User)#1 (1) {
["UserId"]=>
NULL
}
I want to set property A as a protected type.
How can I do this?
Or is there a better way to set the name of my dynamically named property?
The best you can probably do is use magic getter/setter methods and an array of properties:
<?php
abstract class Z
{
private $properties = array();
function __construct()
{
$x = get_called_class();
$this->$x = null;
}
public function __set($prop, $val)
{
$this->properties[$prop] = $val;
}
public function __get($prop)
{
return $this->properties[$prop];
}
}
class A extends Z
{
}
var_dump(new A());
Note that the property is private, child classes will have to go through the __get and __set methods.
You could also restrict dynamic properties to only be the called class name.
<?php
abstract class Z
{
private $classprop;
function __construct()
{
$x = get_called_class();
$this->$x = true;
}
public function __set($prop, $val)
{
if ($prop !== get_called_class()) {
throw new \UnexpectedValueException('Cannot Set Dynamic properties Other than Class Name');
}
$this->classprop = $val;
}
public function __get($prop)
{
if ($prop !== get_called_class()) {
throw new \UnexpectedValueException('Cannot Get Dynamic properties Other than Class Name');
}
return $this->classprop;
}
}
class A extends Z
{
}
I would encourage you to think pretty carefully about why you need dynamic properties like this.
The easiest answer would be don't - just use some generic base property, like protected $Id; and save the trouble.
If you really must have "dynamic" properties in class extensions, probably the simplest would be to declare the property in the extending class:
final class User extends Z {
protected $UserId;
}
Then your code in Z will pick out this protected property. It's psudo-dynamic, since the property name is determined by the coder, and the script only "finds" it when the constructor is run, but if your property name is already determined by something fixed at compile-time, such as the class name, there's functionally no difference.
For truly dynamic property creation, you'd have to add in a runkit, an extension that allows you to programmatically change classes, methods, properties, and functions from within the script itself. A good one seems to be this one by Demitry Zenovich. Unless you have some truly complex functions to carry out to justify the time working with it, though, it ain't going to make your life easier.
I have some variables and functions which need to be available for different classes. Hence, I put all definitions (Variables / functions) to some class:
class common_functions() {
function __construct() {
$this->define_variables();
$this->connect_to_database();
echo "EXEC";
}
function define_variables() {
$this->var1 = "foo";
$this->var2 = "bar";
}
function connect_to_database() {
mysql_connect(...)
}
function do_something() {
//...
}
}
which is the parent of all the others:
class orders extends common_functions {
private $order_item;
function __construct() {
parent::__construct()
$order_item = new item();
}
function show_something() {
echo $order_item->get_something()*$this->var1;
}
}
class item extends common_functions {
pivate $some_number;
function __construct() {
parent::__construct()
$this->number = 123;
}
function get_something() {
return $this->var2*$this->var1*$this->number;
}
}
class some_other_class extends common_functions {
function __construct() {
parent::__construct()
}
// ..
}
However, as executing
$o = new order();
$o->show_something();
the output is
EXEC
EXEC
since the common_functions class is called twice. Especially also mysql-connection is established several times which is quite unefficient.
What I need is some technique so that all the functions and variables (and database-connections) from common_functions are available to all classes without the drawback that e.g. connect_to_database() is executed several times. Some ideas?
If I were you I'd redesign my implementation. Why? Well because it seems to me that neither some_other_class nor item is a common_functions. However they both have common_functions. Thus I'd create only one instance of that class and pass it into the constructor.
Something like this:
class Item {
private $common_functions;
public function __construct($common_functions) {
$this->common_functions = $common_functions;
}
}
class Order {
private $common_functions;
public function __construct($common_functions) {
$this->common_functions = $common_functions;
}
}
What happens now is that both the item and some_other_class objects has a dependency which we inject to common_functions. This obviously means that you have to pass some values to the methods in common_functions but that is a very small price to pay considering what you gain from not inheriting common_functions, like only one db-connection.
Inheritance is cool but in practice it isn't used all that much. It's often much better compose objects than to inherit a bunch of stuff. When designing OO-classes always consider wether an objects relation is an is a or has a relation.
So what you could do using the above example of the orders constructor is the following:
class orders {
private $common_functions;
public function __construct($common_functions) {
$this->common_functions = $common_functions;
$order_item = new Item($common_functions);
}
}
That way both item and order will share the same common_functions object.
Assign a static null variable initially in parent class and check if its null or not.
class common_functions {
private static $dbInstance = null;
function __construct() {
if(self::$dbInstance == null) {
self::$dbInstance = $this->connect_to_database();
}
}
...
return the the database connection handler or any other than the null value in $this->connect_to_database();
class TopParent
{
protected function foo()
{
$this->bar();
}
private function bar()
{
echo 'Bar';
}
}
class MidParent extends TopParent
{
protected function foo()
{
$this->midMethod();
parent::foo();
}
public function midMethod()
{
echo 'Mid';
}
public function generalMethod()
{
echo 'General';
}
}
Now the question is if I have a class, that extends MidParent because I need to call
class Target extends MidParent
{
//How to override this method to return TopParent::foo(); ?
protected function foo()
{
}
}
So I need to do this:
$mid = new MidParent();
$mid->foo(); // MidBar
$taget = new Target();
$target->generalMethod(); // General
$target->foo(); // Bar
UPDATE
Top parent is ActiveRecord class, mid is my model object. I want to use model in yii ConsoleApplication. I use 'user' module in this model, and console app doesn't support this module. So I need to override method afterFind, where user module is called. So the Target class is the class that overrides some methods from model which uses some modules that console application doesn't support.
Try this (http://php.net/manual/en/language.oop5.final.php - not allow to overriding in the childrens):
final protected function foo()
{
$this->midMethod();
parent::foo();
}
in class MidParent and the class Target can't overrides this method.
Directly - you can't. This is how OOP works.
You can do it by a little redesign, e.g. in MidParent add method:
protected function parentFoo()
{
parent::foo();
}
and in Target:
public function foo()
{
$this->parentFoo();
}
But, again, this is only a workaround to solve your question and not a solution.
Actually, you can do this like this way with Reflection::getParentClass():
class Foo
{
public function test($x, $y)
{
echo(sprintf('I am test of Foo with %s, %s'.PHP_EOL, $x, $y));
}
}
class Bar extends Foo
{
public function test()
{
echo('I am test of Bar'.PHP_EOL);
parent::test();
}
}
class Baz extends Bar
{
public function test()
{
$class = new ReflectionClass(get_class($this));
return call_user_func_array(
[$class->getParentClass()->getParentClass()->getName(), 'test'],
func_get_args()
);
}
}
$obj = new Baz();
$obj->test('bee', 'feo'); //I am test of Foo with bee, feo
-but this is an architecture smell in any case. If you need something like this, that should tell you: you're doing something wrong. I don't want to recommend anyone to use this way, but since it's possible - here it is.
#AnatoliyGusarov, your question is interesting and in a sense you can achieve what you desire using yii and php advances features like Traits and Traits in Yii.
Given that it depends on what version of php you are using.However in yii you can achieve this by behaviors and check this SOQ.
In a nutshell you have to use language advanced features or YII framework features to come around this kind of issues,but that boils down to actual requirements