I have two classes. Class B has field: object of class A (composition relationship). It is necessary to get static variable of class A. But there are some problems in code:
<?php
class A {
public static $var = 'a';
}
class B {
private $object;
private function staticAccess($className) {
$this->object = $className;
}
public function __construct() {
$this->staticAccess('A');
// This is wrong syntax:
//$a = $this->object::$var;
// Syntax which works but unconvenient
$objA = $this->object;
$a = $objA::$var;
}
}
As you saw there is a solution. But it is necessary to write additional line. Is it possible to solve a task in one line?
Thanks you for any help!
It's not possible to do in one line (just a constraint of PHP). I'd suggest adding a function that you can use, something like this:
public function getStaticVar($var) {
$class = new ReflectionClass($this->object);
$value = $class->getStaticPropertyValue($var);
return $value;
}
Using the Reflection library is the only way of dynamically accessing a dynamic static property in PHP.
Related
I have a property that stores a class name as a string. I then want to use this to call a static method of said class. As far as I know, this is possible since PHP 5.3. I am running 5.6.x on a vagrant box.
I want to do this:
$item = $this->className::getItem($id);
But I get the following error:
Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)...
The following works fine:
$c = $this->className;
$item = $c::getItem($id);
Any idea why? Is this not the same thing?
The problem is that you are access are property from a class in the first useage, but then in the second try you are parsing the value of the class property (into $c), what is a classname as string, and this can used for static calls to static class functions. The first try, trys to access the static method on an string (the class property).
class a {
static function b(){echo'works';}
}
$a='a';
$a::b();
But the real issue of the error is, that this ->FooBar:: is an syntax error in PHP.
JOUM is completely right!
Based on his answer I wrote a class like a fabric.
Interface GetItem
{
public static function getItem($id);
}
Abstract Class Item
{
private $id;
function __construct($id)
{
$this->id = $id;
}
}
Class ItemA extends Item implements GetItem
{
public static function getItem($id)
{
$item = new ItemA($id);
return $item;
}
}
Class ItemB extends Item implements GetItem
{
public static function getItem($id)
{
$item = new ItemB($id);
return $item;
}
}
Class Fabric
{
function fabricItem($classname,$id)
{
$item = $classname::getItem($id);
return $item;
}
}
$fabric = new Fabric();
$a = $fabric->fabricItem("ItemA",3);
$b = $fabric->fabricItem("ItemB",4);
var_dump($fabric);
var_dump($a);
var_dump($b);
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.
How do I use an object (along with its methods and properties) when I'm inside an object?
Say I have useless classes like these:
class Fruit {
private $name; // Name of the fruit.
private $health = 10; // 0 is eaten, 10 is uneaten.
private $object; // This is a PHP object.
public function __construct($name) {
$this->name = $name;
}
public function set($varname,$value) {
$this->$varname = $value;
}
}
class Eater {
private $name;
public function eat($object) {
$object->set('health',0); // I know I can pass and modify objects like this.
// The object is passed by reference in PHP5 (but not 4), right?
}
}
And I use it as such:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->eat($apple);
?>
But if I modify the Eater class like so:
class Eater {
private $name;
private $objectToEat; // Let's say if I need the object to be over here instead of in a method.
public function set($varname,$value) {
$this->$varname = $value;
}
public function eat() {
$this->objectToEat->set('health',0); // This doesn't work!
}
}
And set the main program like so:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->set('objectToEat',$apple);
$paul->eat();
?>
How can I access the object's properties from inside a method? I know I use $this->objectToEat to tell PHP I'm talking about the class properity, but since that property is an object, how do I access the object's methods?
I've tried $this->objectToEat->set('health',0) but that doesn't work. I hope you guys understand what I'm trying to get at (sorry, I can't figure out how to condense my question without compromising clarity)!
You have to set the property correctly. Since it's private, you can't do this from outside the object, so you have to use encapsulation:
class Eaters {
private $name;
private $objectToEat;
public function eat() {
$this->objectToEat->set('health',0); // Assumed "object" was just a typo
}
public function setObjectToEat($object) {
$this->objectToEat = $object;
}
}
Then use it like so:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->setObjectToEat($apple);
$paul->eat();
?>
Note: In this brief example, your original method is a better design. In certain cases, you might want to prime the method to be used by setting properties beforehand, but more often you want to call it with parameters directly, since it's more clear and more reusable (compartmentalized).
This answer modifies Renesis' answer
In the class, the object to eat is a private variable hence you can't go
$paul->objectToEat = $apple;
What you can do is to make a setter method inside Eaters
class Eaters {
private $name;
private $objectToEat;
public function eat() {
$this->objectToEat->set('health',0); // Assumed "object" was just a typo
}
public function setFood($object) {
$this->objectToEat = $object;
}
}
Therefore, you can call the setFood() method instead.
OR
Change eat() to
public function eat($object) {
$this->object->set('health',0);
return $object;
}
Saving the modified object back to the original variable.
OR
class Eaters {
private $name;
public function eat(&$object) { // this passes object by reference
$object->set('health', 0);
}
}
Although this code is not tested, that is how you can pass a variable by reference.
NOTE: You only need the & when defining the method not when you're passing an argument. For more info about Passing by Reference go to this link
It's probably because your eat method isn't accepting any parameters, and the Eaters class has no $object property.
Can you make $objectToEat a reference and then use it as such in the eat() function?
you have to set $this->object in class Eaters
function __construct($object){
$this->object = $object;
}
or
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->eat($apple);
?>
class Tester {
private $variable;
private $anObj;
public function testFn($val) {
$this->variable = $val;
$this->anObj = new SecondObj();
$this->doSomething();
}
public function doSomething() {
echo("My variable is set to " . $this->variable);
$this->anObj->wow();
}
}
class SecondObj {
public function __construct() {
echo("I'm new!");
}
public function wow() { echo("Wow!"); }
}
$tester = new Tester();
$tester->testFn(42);
Output:
I'm new!My variable is set to 42Wow!
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.
Hi i have a little collection of classes some of which should be globally accessible.
I found something similar in Zend_Registry, but reading its code i cant understand how a call to a static function could return an initialized instance of a class...
i need to do something like:
<?php
//index.php
$obj = new myUsefulObject();
$obj->loadCfg("myFile.xml");
$req = new HTTPRequest();
$req->filter("blablabla");
myappp::registerClass("object",$obj);
myappp::registerClass("request",$req);
$c = new Controller();
$c->execute();
?>
Here i have filtered the Request object and i want the controller to be able to reach that already filtered request.
<?php
class Controller
{
function __construct()
{
$this->request = Application::getResource("request");//This must be the filtered var =(
}
}
?>
I don't know how to implement that Application::getResource(), the only thing i know is that it must be a static method because it can't be related to a specific instance.
Aside from static methods, PHP also has static properties: properties that are local to the class. This can be used to implement singletons, or indeed a Registry:
class Registry {
private static $_registry;
public static function registerResource($key, $object)
{
self::$_registry[$key] = $object;
}
public static function getResource($key) {
if(!isset(self::$_registry[$key]))
throw InvalidArgumentException("Key $key is not available in the registry");
return self::$_registry[$key];
}
}
1: You can acess global variables with the global keyword:
$myVar = new SomethingProvider();
class MyClass {
public function __construct() {
global $myVar;
$myVar->doSomething();
}
}
2: You can do the same using the $GLOBALS super-global:
$myVar = new SomethingProvider();
class MyClass {
public function __construct() {
$GLOBALS['myVar']->doSomething();
}
}
3: You can define a singleton class (the wikipedia has a nice example, too).
4: You could add globals as public static members (or private static members with public getters/setters) to a class:
class Constants {
const NUM_RETIES = 3;
}
if ($tries > Constants::NUM_RETRIES) {
# User failed password check too often.
}
class Globals {
public static $currentUser;
}
Globals::$currentUser = new User($userId);
I wouldn't recommend the first two methods, overwriting the values of these global variables unintentionally is too easy.
Seems to me like you might need some form of Singleton design pattern;
Check this out!
Hope it helps!