PHP - Two classes, talk to each other correctly - php

I have a small problem. I've tried searching, but I can't get the search terms quite right and was hoping someone could help.
I have an include on every page in my system that works something like this:
<?PHP
require_once("class.system.php");
require_once("class.mysql.php");
$oMySQL = new MySQL();
$oSystem = new SystemClass();
... ?>
But I have a problem. As you may guess - the MySQL class is a bunch of functions that I use to make MySQL calls easier. This isn't the only example of where I want to use it but it's a good example.
I have functions in the system class I want to be able to reference the MySQL class (And vice versa...).
As an example, I have a function in the system class that will populate a session variable with data from MySQL. The only way I can think of doing this (Which I know is wrong...) is:
class SystemClass {
function PopulateSession(){
global $oMySQL;
if($oMySQL->Select('abc')){
$_SESSION['def']= blahblahblah;
return true;
} else {
return false;
}
}
}
It works, but it means every function I want to use it, I have to use global, which I'm sure is very bad practice. Could someone advise??
Thanks

What you encountered is called composition. A good solution would be to use a dependency injection framework. An easy solution is to roll with constructor parameters.
public class A {
private $b;
public function __construct($b) {
$this->b = $b;
}
}
$b = new B;
$a = new A($b);
Or, as a more flexible solution, when you have mutual dependencies:
public class A {
private $b;
public function setB($b) {
$this->b = $b;
}
}
public class B {
private $a;
public function setA($a) {
$this->a = $a;
}
}
$a = new A;
$b = new B;
$a->setB($b);
$b->setA($a);
But the downside is that as the number of dependencies grows, it's hard to manage and remember to set all the dependencies. This is exactly the reason why Dependency Injection frameworks are popular.

Related

Is there any performance difference when passing objects in function parameter based on object size?

I have class A, B, C, D
class A {
public $b;
public $c;
public $d;
// Other properties
function __construct() {
$this->b = new B();
$this->c = new C();
$this->d = new D();
}
function process() {
$x = new ExternalClass($this->b, $this->c, $this->d)
// $x = new ExternalClass($this)
}
// other functions.
}
Here, is there any performance deference passing parameter as $this instead of $this->b, $this->c, $this->d ?
Later, i may need to send more objects $this->e, $this->f etc. Instead of passing each object variables, if i passing $this object I can access whatever objects i want. But I want know is there any performance issue involved in this.
In this case, you really don't need to worry about the performance. You never measure difference in real world application.
What I would be woried much more is your implementation. Read something about Dependency Injection (DI) and try decouple your application to more classes using Single Responsibility Principle (SRP).

Circular dependency - Injecting objects that are directly depended on each other

I have used Dice PHP DI container for quite a while and it seems the best in terms of simplicity of injecting dependencies.
From Dice Documentation:
class A {
public $b;
public function __construct(B $b) {
$this->b = $b;
}
}
class B {
}
$dice = new \Dice\Dice;
$a = $dice->create('A');
var_dump($a->b); //B object
However, when you have to use objects that are directly dependent on each other, the finall result is server error, because of the infinite loop.
Example:
class A {
public $b;
public function __construct(B $b) {
$this->b = $b;
}
}
class B {
public $a;
public function __construct(A $a) {
$this->a = $a;
}
}
Author of Dice says that there is no way to construct an object from the A or B classes. As:
An 'A' object requires a 'B' object to exist before it can be created
But a 'B' object requires an 'A' object to exist before it can be created
Author says, that this limitation concerns all DI containers!
Question:
What would be the best solution for overcoming this problem nicely without changing initial code? Could anyone provide an example of using other DI containers, when it would be possible to run exampled code without bulky workarounds?
As mentioned on your post on the Dice github ( https://github.com/TomBZombie/Dice/issues/7 ), the only way to resolve without removing the circular dependency is to refactor one of the classes to use setter injection:
class A {
public $b;
public function __construct(B $b) {
$this->b = $b;
}
}
class B {
public $a;
public function setA(A $a) {
$this->a = $a;
}
}
This allows the objects to be constructed:
$b = new B();
$a = new A($b);
$b->setA($a);
With the original code:
class A {
public $b;
public function __construct(B $b) {
$this->b = $b;
}
}
class B {
public $a;
public function __construct(A $a) {
$this->a = $a;
}
}
You cannot construct it and run into the same problem as the container:
$b = new B(new A(new B(new A(new B(.............))))
The problem with having a container work around this issue using a hack such as ReflectionClass::newInstanceWithoutConstructor is that your objects are now dependent on creation logic which uses this method. You essentially couple the code to the container which is a poor design as your code is now no longer portable and cannot be used without the container to perform the object construction.
You have a circular dependency, which is very hard to solve. The first thing to do is to try to get rid of this circular dependency by refactoring your classes and how they interact.
If you really can't manage to do it, there are solutions. I'll copy-paste my answer from Self-referencing models cause Maximum function nesting level of x in Laravel 4:
Setter injection
Rather than injecting a dependency in the constructor, you can have it injected in a setter, which would be called after the object is constructed. In pseudo-code, that would look like that:
$userRepo = new UserRepository();
$cartRepo = new CartRepository($userRepo);
$userRepo->setCartRepo($userRepo);
Lazy injection
I don't know if Dice does support lazy injection, but that's also a solution: the container will inject a proxy object instead of the actual dependency. That proxy-object will load the dependency only when it is accessed, thus removing the need to build the dependency when the constructor is called.
Here is an explanation on how lazy injection works if you are interested: http://php-di.org/doc/lazy-injection.html

php Set a anonymous function in an instance

I am just starting out with PHP, and I am wondering if there is a way to add an anonymous function to a class instance.
For instance, lets say...
class A{
public B;
}
$c = new A();
//This is where I am getting a little confused...
//The following wont work
$c->B = function(){echo('HelloWorld');};
$c->B();
What I am hoping to do is reuse the same spit of code in a great number of different applications, and make it so that I can just 'swap-out' and replace functions in specific instances.
I am using php5.3 (so anonymous functions should work, just not in the way that I am using them).
Thanks so very much for your time!!
-GK
You can use the __call magic function for this job. Not a beauty, but it works..
like this:
class A {
public $B;
public function __call($closure, $args)
{
call_user_func_array($this->$closure, $args);
}
}
$c = new A();
$c->B = function () { echo('HelloWorld'); };
$c->B();
FWIW:
PHP 5.3's treatment of anonymous functions is entertaining. This won't work:
$c->B = function() { echo func_get_arg(0); };
$c->B("This fails :(");
This WILL work:
$c->B = function() { echo func_get_arg(0); };
$hilarious = $c->B;
$hilarious("This works!");
To work around this, you need to use a __call hack like the one provided by Oden.
This behavior may change in the future. The array dereferencing RFC was recently committed to PHP's trunk, and the patch has set off a discussion on function call chaining, the syntax of which may allow what you're trying to do without the __call hack. Unfortunately it's proven difficult in the past to get function call chaining working.
# real ugly, but PoC...
class a {
function __call($f, $x) {
call_user_func_array($this->$f, $x);
}
}
$a = new a;
$a->b = function() { echo "Hello world"; };
$a->b();
Sounds like you are describing a Strategy Pattern or Decorator Pattern - there are other ways to achieve this in way which is more easily communicated with other developers who read your code.
You can do something along these lines (which will also work with callbacks that are not closures):
<?php
class A {
private $fun;
function setFun($fun) {
if (!is_callable($fun))
throw new InvalidArgumentException();
$this->fun = $fun;
}
public function fun() {
call_user_func_array($this->fun, func_get_args());
}
}
$c = new A();
$c->setFun(function($a) { echo('HelloWorld ' . $a);});
$c->fun("here");
which gives HelloWorld here.
That said, you should also consider inheritance or the decorator pattern.
This is not an issue anymore by PHP 7;
// no error
$result = ($this->anonFunc)();
$result = ($this->anonFunc)($arg1, $arg2, ...);
See more about AST.
Rather than hooking a __call magic method into your class, you can instead execute the callable directly using call_user_func.
class A {
public $b;
}
$c = new A();
$c->b = function(){echo('HelloWorld');};
call_user_func($c->b); // HelloWorld
Obviously it would be nice for PHP to provide some syntax to execute this directly.

Dynamically creating instance variables in PHP classes

I'm not sure if this is a trivial questions but in a PHP class:
MyClass:
class MyClass {
public $var1;
public $var2;
constructor() { ... }
public method1 () {
// Dynamically create an instance variable
$this->var3 = "test"; // Public....?
}
}
Main:
$test = new MyClass();
$test->method1();
echo $test->var3; // Would return "test"
Does this work?? How would I get this to work? Ps. I wrote this quickly so please disregard any errors I made with setting up the class or calling methods!
EDIT
What about making these instance variables that I create private??
EDIT 2
Thanks all for responding - Everyone is right - I should have just tested it out myself, but I had an exam the next morning and had this thought while studying that I wanted to check to see if it worked. People keep suggesting that its bad OOP - maybe but it does allow for some elegant code. Let me explain it a bit and see if you still think so. Here's what I came up with:
//PHP User Model:
class User {
constructor() { ... }
public static find($uid) {
$db->connect(); // Connect to the database
$sql = "SELECT STATEMENT ...WHERE id=$uid LIMIT 1;";
$result = $db->query($sql); // Returns an associative array
$user = new User();
foreach ($result as $key=>$value)
$user->$$key = $value; //Creates a public variable of the key and sets it to value
$db->disconnect();
}
}
//PHP Controller:
function findUser($id) {
$User = User::find($id);
echo $User->name;
echo $User->phone;
//etc...
}
I could have just put it in an associative array but I can never correctly name that array something meaningful (ie. $user->data['name'] ... ugly.) Either way you have to know what is in the database so I do not really understand what the argument is that its confusing, especially since you can just var dump objects for debugging.
Why dont you just write the code and see for yourself?
<?php
class Foo
{
public function __construct()
{
$this->bar = 'baz';
}
}
$foo = new Foo;
echo $foo->bar; // outputs 'baz'
and
var_dump($foo);
gives
object(Foo)#1 (1) {
["bar"] => string(3) "baz"
}
but
$r = new ReflectionObject($foo);
$p = $r->getProperty('bar');
var_dump($p->isPublic());
will throw an Exception about 'bar' being unknown, while
$r = new ReflectionObject($foo);
$p = $r->getProperties();
var_dump($p[0]->isPublic());
will return true.
Now, should you do this type of assignment? Answer is no. This is not good OOP design. Remember, OOP is about encapsulation. So, if bar is describing some public property of the class, make it explicit and declare it in your class as public $bar. If it is supposed to be private declare it as private $bar. Better yet, dont use public properties at all and make them protected and provide access to them only through getters and setters. That will make the interface much more clearer and cleaner as it conveys what interaction is supposed to be possible with an object instance.
Assigning properties on the fly here and there across your code, will make maintaining your code a nightmare. Just imagine somewhere along the lifecylce of Foo someone does this:
$foo = new Foo;
$foo->monkey = 'ugh';
echo $foo->monkey; // outputs 'ugh'
Now, from looking at the class definition above, there is absolutely no way, a developer can see there is now a monkey patched into Foo. This will make debugging a pain, especially if code like this is frequent and distributed across multiple files.
Yes that will indeed work. Auto-created instance variables are given public visibility.
yes that works as you'd hope/expect.
I you wanted to make private variables on the fly you could use php magic functions to emulate this, e.g
MyClass
<?php
class MyClass {
public $var1;
public $var2;
private $data = array();
public function __get($key) {
// for clarity you could throw an exception if isset($this->data[$key])
// returns false as it is entirely possible for null to be a valid return value
return isset($this->data[$key]) ? return $this->data[$key] : null;
}
public function __set($key, $value) {
$this->data[$key] = $value;
}
}
?>
Main
<?php
$test = new MyClass();
$test->myVar = 'myVar is technically private, i suppose';
echo $this->myVar; // 'myVar is technically private
?>
Although these dynamically created variables are technically private, they are infact publicly accessible... i cannot image the purpose for wanting to dynamically create private instance variables. I would question your design.
Did you try it?
It is possible but you might get strict errors. If you dynamically need to create these variables, you are probably doing something wrong.
You should either change this into a function:
function var($no) { .. }
or use __get (http://ca.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members)

Reference and Overwriting

I have:
class A{
public $name = 'A';
public $B;
public function B_into_A($b)
{
$this->B = $b;
}
}
class B{
public $name = 'B';
public $A;
public function new_A_into_B($a)
{
$this->A = new $a;
}
}
$a = new A;
$b = new B;
$a->B_into_A($b);
$b->new_A_into_B('A');
Is this a good way to insert another class inside a "main" class at the beginning of the runtime?
Should I use references?
(Background: I currently work on a MVC framework in which I have to handle many classes within some main classes e.g. bootstrapper, wrapper, modules, adapter etc.)
Yes and No...
Your first function call was fine, I would just use a more standard name:
$a = new A;
$b = new B;
$a->setB($b); // B_into_A is a little bit of a whacky function name
Your second call, it doesn't really make sense to pass a string and then create the object (Unless you're looking for some sort of factory). If you want B to own A:
$b->new_A_into_B( new A );
public function new_A_into_B($a)
{
$this->A = $a;
}
Again i don't like the name.. Id probably go with setA() there as well.
Passing an object instead of its class name makes sense because then it is easier for the garbage collector to guess when it is not needed anymore.
<?php
class A {
public $B;
}
class B {
public $A;
}
$a = new A;
$b = new B;
$a->B = $a;
$b->A = $b;
Furthermore, I'd try to get rid of the setter methods. In practice the only benefit they provide is to validate input. Since it's not the case here, I'd advise you to directly assign the classes.
You asked "Should I use references?". Actually all objects are passed by reference since PHP5. The only way to get an exact copy of them is to use the clone keyword.
By the way, you do not need to store the class name within each object. Just use get_class().

Categories