Simulating friend classes in PHP - php

I have a class Foo with a number of public and private methods. One of those methods is getting rather large, and I would like to fork it off into a separate class specifically for that purpose. Something like this:
<?php
class Foo
{
// ...
public function doX( $a, $b )
{
$x = new FooXDoer;
$x->foo = $this;
return $x->run( $a, $b );
}
// ...
}
class FooXDoer
{
public $foo;
public function run( $a, $b )
{
// ...
}
// ...
}
FooXDoer has access to Foo's public methods and properties through $this->foo.
How can I give FooXDoer access to Foo's private methods and properties, without making them public to the rest of the code which already uses Foo?
Should I create a separate class FooPrivate which has the private methods as public, and which Foo wraps, and then have FooXDoer reference that? What should FooPrivate be called?
Or is my approach completely wrong? How do you solve this problem in general?

Looks like traits solve your problem best in case you use PHP >= 5.4.
If not, I thought of the following solution:
class A {
private static $allowedClasses = array('B');
private $a = 1;
public function __get($property) {
$caller = debug_backtrace(false);
if(!isset($caller[1]))
throw new Exception('Bla bla');
if(!in_array($caller[1]['class'], self::$allowedClasses))
throw new Exception('Bla bla');
return $this->$property;
}
public function testB() {
$b = new B();
$b->instA = $this;
echo $b->getA();
}
}
class B {
public $instA;
public function getA() {
return $this->instA->a;
}
}
class C {
public function getA() {
$instA = new A();
return $instA->a;
}
}
$a = new A();
$a->testB(); // Works ok;
$c = new C();
$c->getA(); // Throws exception here;
This code is definitely not a best practice :) But since it is possible I put it here.

PHP has no friend class concept, from what I've read I wouldn't say it's a bad decision by the php designers...
IMHO, there is no general strategy, as the problem or question is too broad: there are too many factors to consider:
how many private properties and methods of Foo are needed in run()?
from an abstraction point of view: how closely is run() entangeled in Foo? Does it really "deserve" to be in an independent class?
will you ever use FooXDoer outside of Foo?
Two ideas for solutions:
hand over the needed data from foo to fooDoer, either value for value or by implementing a compileRunData() on Foo that returns an array or an object
public function doX( $a, $b )
{
$x = new FooXDoer;
$workEnvironment = $this->compileRunData();
$x->setEnvironment( $workEnvironment );
$x->foo = $this;
return $x->run( $a, $b );
}
or use inheritance, especially the concept of protected properties:
abstract class FooAbstract
{
protected $_basicVar1;
protected function basicMethod1(/*...*/) {
//...
}
// ...
}
abstract class FooRunner extends FooAbstract
{
protected $_runVar1;
protected function runMethod1(/*...*/) {
//...
}
public function run($a, $b) {
// ...
}
}
public class Domain_Model_Foo extends FooRunner
{
}
edit: hey, SO didn't show me there was already an answer. Yea, thought about traits, too, but haven't used them until now so can't really comment on them

Related

How to solve method overloading in subclass (Declaration of ... should be compatible with )?

The example should demonstrate it best:
class Generic {
protected $a;
protected $b;
protected final function __construct($a,$b) {
$this->a = $a;
$this->b = $b;
echo $this->a." ".$this->b;
}
public static function create($a,$b) {
return new self($a,$b);
}
}
class Wanter extends Generic {
public static function create($b) {
return parent::create("I want",$b);
}
}
Generic::foo("I need","coffee!");
Wanter::foo("coffee!");
Expected output:
I need coffee!I want coffee!
Actual output:
Warning: Declaration of Wanter::create($b) should be compatible
with Generic::create($a, $b) in [...][...] on line 25 I need coffee!I want coffee!
It is obvious what this should do (as it does). However I want to run this without throwing warnings of course. How to implement this without warning?
It should be obvious but the child method definition must match that of the parent, so you are missing an argument.
What I would do is this:
class Generic {
protected $a;
protected $b;
protected final function __construct($a,$b) {
$this->a = $a;
$this->b = $b;
echo $this->a." ".$this->b;
}
public static function create($a,$b) {
return new self($b,$a); //reverse arguments
}
}
class Wanter extends Generic {
public static function create($a, $b="I want") {
return parent::create($b,$a);
}
}
Note that I changed the order of the arguments, this way the one with the default is the second argument.
You could do this just in the child, but it might be somewhat confusing, if the order is different then the parent class.
That said, something like a factory method may be more appropriate in this instance.
https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)
Besides a factory pattern I am not sure how important it is for you to have the static Create method. The constructor offers more flexibility when needing things like polymorphism. For example something like this would be acceptable
abstract class Generic {
protected $a;
protected $b;
protected function create($a,$b) {
$this->a = $a;
$this->b = $b;
echo $this->a." ".$this->b;
}
}
class Wanter extends Generic {
public function __construct($a) {
return $this->create("I want",$a);
}
}
Then each child can define it's own constructor, with its own set of required arguments.

PHP call parent class method

class Foo {
protected static $a = 1;
protected $b = 2;
public function func() { return 'foo' . static::$a . $this->b; }
}
class Bar extends Foo {
protected static $a = 3;
protected $b = 4;
public function func() { return 'bar' . static::$a . $this->b; }
}
$obj = new Bar();
$obj->func(); // returns of course 'bar34'
Is there any option in PHP to call func() from Foo class?
In C++ I would cast $obj to Foo and simply call func()
Bar* obj = new Bar();
Foo* obj2 = (Bar*) obj;
obj2->func(); // returns 'foo14';
If you want to get down and dirty with Reflection then it's possible, but I'd strongly argue that this shouldn't be used anywhere near any production code. If you've got an instance of a child class, then you've got it for a reason, and if it's overridden a parent method then that has also happened for a reason.
Assuming you already know all this, then with that disclaimer out of the way, this should work in any remotely recent version of PHP:
class Foo { public function func() { echo 'I am the parent'; } }
class Bar extends Foo { public function func() { echo 'I am the child'; } }
// Create instance of child class
$bar = new Bar;
// Create reflection class
$reflected = new ReflectionClass(get_class($bar));
// Get parent method
$method = $reflected->getParentClass()->getMethod('func');
// Invoke method on child object
$method->invokeArgs($bar, []);
// I am the parent
See https://3v4l.org/NP6j8
This to me looks like a design issue more than anything else.
However if I were to handle this in a way that were easily readable and without rethinking my design I would do:
<?php
class Foo {
public function func() { return 'foo'; }
}
class Bar extends Foo {
public function func() { return 'bar'; }
public function parentFunc() { return parent::func(); }
}
$obj = new Bar();
$obj->parentFunc(); // returns of course 'foo'
Loek's answer also works, but doesn't call the method on the objects parent. It just calls the method on the classes parent. It all depends on the functionality you are looking for.
You could also do something like:
<?php
class Foo {
public function func() { return 'foo'; }
}
class Bar extends Foo {
public function func($parent = false) {
if ($parent) {
return parent::func();
}
return 'bar';
}
}
$obj = new Bar();
$obj->func(true); // returns of course 'foo'
Which is similar but without the need for the extra method.
Personally though I feel this issue likely requires a rethink in code design more than a coding solution.
-- edit --
To elaborate on 'a rethink in code design', I would ask myself "Why do I need an object that has two methods with the same name, but different functionalities? Is this not a job for two different objects? Trace the issue backwards until you find the design issue. Or the point at which the decision needs to be made as to which object your framework requires.
This isn't exactly what I'd call pretty, but it works and is relatively similar to what you described for C++; It works by calling get_parent_class() and then abusing PHP's ability to create objects from strings.
<?php
class Foo {
public function func() { echo 'foo'; }
}
class Bar extends Foo {
public function func() { echo 'bar'; }
}
$obj = new Bar();
$obj->func(); // Prints 'bar'
$parentClassString = get_parent_class($obj);
$newObj = new $parentClassString; // Gotta love PHP for magic like this
$newObj->func(); // Prints 'foo'
See this snippet to see it in action.
EDIT
It's a lot of work, but you could use so called Late Static Binding, perhaps more clearly explained in Jokerius's answer here. This requires you to write a crapload of custom code though, which I don't think is preferential. Overall the short answer seems to be: it isn't really possible.
I don't know should it help you but try to add this function in Bar class
public function callParent($function){
return parent::$function();
}
and call
echo $obj->callParent("func");
[UPDATED]
Also you can write cast function yourself
something like this
public function castAs($newClass) {
$obj = new $newClass;
foreach (get_object_vars($this) as $key => $name) {
$obj->$key = $name;
}
return $obj;
}

How to use child class to change parents property

I'm trying to change a property in my parent class with my child class but I'm not getting the result I'm expecting.
I've done some research (like Change parent variable from child class), but I can't seem to find the problem.
class A {
public $msg;
public function __construct() {
$this->msg = 'foo';
}
public function setMessage($string) {
$this->msg = $string;
}
public function getMessage() {
var_dump($this->msg); // For demo purposes
}
public function triggerB() {
$b = new B;
}
}
class B extends A {
public function __construct() {
parent::setMessage('bar');
}
}
$a = new A;
$a->getMessage();
$a->triggerB();
$a->getMessage();
The output I get is "foo" twice and I expect it to be "foo" "bar".
Could anyone explain me what i'm doing wrong and how I can fix this?
In my actual code I want the child-class to validate some $_POST values, and return the outcome to the Main-class. The parent uses the child to validate.
You are having your object A and creating an instance of it and storing it in the variable $a, in the global scope. And then you are creating another instance of your class B and storing it in a variable $b which is in the scope of the method triggerB().
You can only change the properties of the parent class A if you pass an argument to your another class B.
So something like this should suffice:
<?php declare(strict_types = 1);
class A {
public $msg;
public function __construct() {
$this->msg = 'foo';
}
public function setMessage(string $string) {
$this->msg = $string;
}
public function getMessage() {
var_dump($this->msg); // For demo purposes
}
public function triggerB() {
(new B($this));
}
}
class B {
public function __construct(A $a) {
$a->msg = "bar";
}
}
$a = new A;
$a->getMessage();
$a->triggerB();
$a->getMessage();
This approach is better suited to readability and better dependency management.
Another approach:
<?php declare(strict_types = 1);
class A {
public $msg;
public function __construct() {
$this->msg = 'foo';
}
public function setMessage(string $string) {
$this->msg = $string;
}
public function getMessage() {
var_dump($this->msg); // For demo purposes
}
public function triggerB() {
$this->msg = 'bar';
}
}
class B {
public function __construct(A $a) {
$a->msg = "bar";
}
}
$a = new A;
$a->getMessage();
$a->triggerB();
$a->getMessage();
This is performance wise better, but if you are going to be doing something complex, the first method is better.
Note: The above code is for PHP7.
Your triggerB() method does not actually do anything:
public function triggerB() {
$b = new B;
}
You are creating a new object and assign that to the $b variable. As soon as the method finishes, the $b variable / object ceases to exist.
Also note that the $b variable in your method is is no way related to the $a variable in the global scope so setting any of its properties has no influence on $a.

calling a class function from another class function

I'm new to programming. I have this going on:
I have Class A, which have many functions. One of those functions is functionX.
In functionX I need to make a call to functionY which belongs to another class: Class B.
So how do I acces to functionY from inside functionX?
I use Codeigniter.
Thanks in advance.
Try and experiment with this.
class ClassA {
public function functionX() {
$classB = new ClassB();
echo $classB->functionY();
}
}
class ClassB {
public function functionY() {
return "Stahp, no more OO, stahp!";
}
}
Class function? A static method?
If you have an instance (public) method, you just call $classB->functionY().
If you have a static method, you would call ClassB::functionY();
So:
class ClassA {
public function functionX(){
$classB = new ClassB();
// echo 'foo';
echo $classB->functionY();
// echo 'bar';
echo ClassB::functionYStatic();
}
}
class ClassB {
public $someVar;
public static $someVar2 = 'bar';
function __construct(){
$this->someVar = 'foo';
}
public function functionY(){
return $this->someVar;
}
public static function functionYStatic(){
return self::$someVar2;
}
}
Well that depends. If that function is a static function or not.
First off you must include the file with the class...
include_once('file_with_myclass.php');
If it is static you can call it like this:
ClassName::myFunction()
If it is not, then you create an instance of the class and then call the function on that instance.
$obj = new ClassName();
$obj->myFunction();
As you can guess the function being static means you can call it without the need of creating an instance. That is useful for example if you have a class Math and want to define a function that takes to arguments to calculate the sum of them. It wouldn't really be useful to create an instance of Math to do that, so you can declare as static and use it that way.
Here's a link to the docs with further info
http://www.php.net/manual/en/keyword.class.php
If functionY is static you can call ClassB::functionY(). Else you must create instance of Class B first. Like:
$instance = ClassB;
$instance->functionY();
But maybe you mean something else?
Looks like one of your class has a dependency to another one:
<?php
class A
{
public function x()
{
echo 'hello world';
}
}
class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
public function y()
{
$this->a->x();
}
}
$a = new A();
$b = new B($a);
$b->y();
Depending how your code looks like, if it makes sense, you can inject class A into y()
public function y(A $a)
{
// your code with $a
}

calling a function of a class created in class in php

Here is the code layout outline all nicely laid out in 3 file and class's
$aa = new className();
class className {
/**
* Constructor
*/
function className() {
$this->init_SubClass();
}
function init_SubClass() {
require_once('sub_class.class.php');
$sub_class = new sub_class();
}
}
sub_class.class.php
class sub_class {
/**
* Constructor
*/
function sub_class() {
$this->init_Sub_Sub_Class();
}
function init_Sub_Sub_Class() {
require_once('Sub_Sub_Class.class.php');
$Sub_Sub_Class = new Sub_Sub_Class();
}
}
sub_sub_class.class.php
class Sub_Sub_Class {
public function function_I_to_call() {
echo ' show this text'
}
}
How to a call function_I_to_call()
This was mybest guess so far
$aa->className->sub_class->function_I_to_call()
Not sure how to do this or if it can be done.
Many Thanks
You are not assigning the newly created object to the instance. You need to use
$this->sub_class = new Subclass;
That will make them public properties and then you can use your
$aa = new className;
$aa->sub_class->function_I_to_call();
However, the entire approach is completely flawed:
The constructor should be __construct. The old style constructor is a relic from PHP4 times and wont work with namespaced classes.
Assigning properties on the fly is considered bad practice, because it's unobvious they exist when looking at the API. Declare them as members in the class.
Calls to require are unneeded when you use an Autoloader.
Use Dependency Injection to decouple your components. Makes them easier to unit-test as well.
If you need to assemble complex collaborator graphs, use a Factory or a Builder pattern instead.
Alternate approach
class Foo
{
protected $bar;
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
public function getBar()
{
return $this->bar;
}
}
And then Bar
class Bar
{
protected $baz;
public function __construct(Baz $baz)
{
$this->baz = $baz;
}
public function getBaz()
{
return $this->baz;
}
}
And Baz:
class Baz
{
public function fn()
{
return 'called';
}
}
And then assemble it via:
$foo = new Foo(new Bar(new Baz));
Or move that code to a Factory:
class FooFactory
{
public function create()
{
return new Foo(new Bar(new Baz));
}
}
Finally, the Autoloader (simplified):
spl_autoload_register(function($className) {
$classMap = array(
'Foo' => '/path/to/Foo.php',
'Bar' => '/path/to/Bar.php',
'Baz' => '/path/to/Baz.php',
);
require $classMap[$className];
});
And then you could call (demo)
$fooFactory = new FooFactory;
$foo = $fooFactory->create();
echo $foo->getBar()->getBaz()->fn();
But you shouldnt (unless it's some sort of DSL), because that is violating Law of Demeter because you are digging too deep into the collaborators.

Categories