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.
Related
How can I create something like
MyObject->property->method()
in PHP?
I only know how to create a method for a class:
class MyObject
{
public function MyMethod()
{
// do something
}
}
In Javascript I can easily do something like
var MyObject = {
property : {
method : function ()
{
// do something
}
}
}
How do I do that?
In Javascript you can create objects and methods inline, in PHP you need to have a class and instantiate it:
class Foo {
public function method() {}
}
class MyObject {
public $property;
public function __construct() {
$this->property = new Foo;
}
}
$o = new MyObject;
$o->property->method();
You can set an object as the value of a property. Something like this:
class Foo {
public $Bar;
public function __construct() {
$this->Bar = new Bar();
}
}
class Bar {
public function ShowBar() {
echo 'Bar';
}
}
$Foo = new Foo();
$Foor->Bar->ShowBar();
As others have correctly answered, this works differently in PHP and Javascript. And these differences are also the reason why in PHP you need to define the class methods before you run them. It might become a bit more dynamic in the future but I'm sure not on the level of Javascript.
You can however fake this a bit in PHP because you can assign functions to properties dynamically:
$myObject = new PropCall;
$myObject->property->method = function() {
echo "hello world\n";
};
$myObject->property->method();
This example outputs:
hello world
This does work because some little magic has been added in the instantiated object:
class PropCall
{
public function __call($name, $args) {
if (!isset($this->$name)) {
return null; // or error handle
}
return call_user_func_array($this->$name, $args);
}
public function __get($name) {
$this->$name = new PropCall;
return $this->$name;
}
}
This class code checks if a dynamic property has been added with the name of the method called - and then just calls the property as a function.
Is it bad instantiating objects in the constructor like this below?
class Foo
{
public function fooMethod() {
return 'foo method';
}
}
class Too
{
public function tooMethod() {
return 'too method';
}
}
class Boo
{
public $foo;
public $too;
public function __construct()
{
$this->foo = new Foo();
$this->too = new Too();
}
}
If so, how bad can it be? How should it be done properly?
Manually instantiating classes inside another class creates implicit dependencies, which are quite hard to maintain - you will have a hard time detecting what needs to be changed if you ever need to change those Foo and Too classes.
So, a better way of managing dependencies is:
class Foo
{
private $_bar;
function __construct(Bar $bar)
{
$this->_bar = $bar;
}
}
This way, your object dependency is explicit. Another advantage of doing this, is that some PHP frameworks, (Laravel, Zend, Symfony), allow for an automatic dependency resolution. It means, that you don't instantiate your object manually, only via some sort of factory - like this (Laravel):
$foo = App::make('Foo');
And an App factory automatically detects your Foo class dependencies with some reflection magic and injects them appropriately. Other frameworks have similar capabilities, too.
Also, there are some general principles in OOP, called SOLID which help to develop better OOP design. One of them - D, stands for Dependency Inversion. What it means, is that you should avoid hard dependencies, like in your code. Instead, both Foo and Bar classes should depend on an interface, like this:
interface BarInterface
{
function doBar();
}
class Bar implements BarInterface
{
function doBar()
{
print "Doing BAR";
}
}
class Foo
{
/**
* #var BarInterface
*/
private $bar;
function __construct(BarInterface $bar)
{
$this->bar = $bar;
}
}
Now, if you ever need to change that Bar class with something else, all hell won't break loose, if your replacement also implements that BarInterface.
It's not inherently bad.
The downside is that it decreases the "testability" of your class, simply because Boo is now dependent on the existence Foo and Too.
This depends on the size of your project.
On large projects, or long term projects, it should be changed slightly.
Ideally, you would refactor it implement Dependency Injection pattern, and maybe use a Factory to instantiate it.
Some sample code:
interface FooInterface { function fooMethod(); }
class Foo implements FooInterface { function fooMethod(){return 'Foo';} }
interface TooInterface { function tooMethod(); }
class Too implements FooInterface { function tooMethod(){return 'Too';} }
class Boo
{
public $foo;
public $too;
public function __construct(FooInterface $foo, TooInterface $boo)
{
$this->foo = $foo;
$this->too = $boo;
}
}
class BooFactory
{
public static function create()
{
return new Boo(new Foo, new Too);
}
}
It depends of your requirement and the classes.
Let's says that every call to the constructor of Foo/Too you will execute a huge query to the database to get data, in that scenario I would opt to use lazy instantiation.
Of course, it's a good practice to initialize your properties on the constructor, but on real life performance could your enemy.
Example:
class Boo {
private $foo = null;
private $too = null;
public function __construct() {
//Do something else
}
public function getFoo() {
if (is_null($this->foo)) {
$this->foo = new Foo();
}
return $this->foo;
}
public function getToo() {
if (is_null($this->too)) {
$this->too = new Too();
}
return $this->too;
}
public function aMethodThatUsesFoo() {
$foo = $this->getFoo();
$foo->fooMethod();
}
public function aMethodThatDoesntUsesFoo() {
echo "Hello!, I don't need foo or too to execute this method";
}
}
if you use this class only to execute aMethodThatDoesntUsesFoo(), it will never call the constructors of Foo/Too.
$boo = new Boo();
$boo->aMethodThatDoesntUsesFoo();
if you will only execute aMethodThatUsesFoo(), it will only instantiate Foo
$boo = new Boo();
$boo->aMethodThatUsesFoo();
You can do this by static methods as well.
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
Basically this is what i want to do:
<?php
class App {
public $var = "main-class";
public function load() {
$this->var = "child-class";
$child = new Child;
$child->echo_var();
}
}
class Child extends App {
public function echo_var() {
echo $this->var;
}
}
$app = new Child;
$app->load();
?>
It outputs "main-class", i want it to output "child-class" without having to modify the child class (because i want it to be sort of a "clean" and dynamic class).
I accept suggestions for another course of action
PS: This is part of an Small MVC Framework i'm trying to develop.
There are two ways that you could do this. Both are going to need to use constructors. With the first one, the child will declare itself when created
<?php
class App {
public $var = "main-class";
public function __construct($var=null) {
if($var !== null) {
$this->var = $var;
}
}
public function load() {
$child = new Child ();
$child->echo_var();
}
}
class Child extends App {
public function __construct(){
parent::__construct("child-class");
}
public function echo_var() {
echo $this->var;
}
}
$app = new Child();
$app->load();
?>
The second one allows the parent to declare the name of the child.
<?php
class App {
public $var = "main-class";
public function __construct($var=null) {
if($var !== null) {
$this->var = $var;
}
}
public function load() {
$child = new Child ("child-class");
$child->echo_var();
}
}
class Child extends App {
public function echo_var() {
echo $this->var;
}
}
$app = new Child();
$app->load();
?>
Both of those examples work and do what you want, I believe.
This isn't how inheritance works - By creating a new Child object, its data members are all initialized with their default values. When you do $this->var = "" in the parent class, you're setting the data members for the $app object, not the $child object.
You can modify the child class to incorporate a constructor that accepts parameters, and that constructor would set its data members properly. To achieve something similar to what you want, you can use constructors:
<?php
class App {
public $var = "main-class";
public function __construct() {
$this->var = "child-class";
}
public function load() {
$child = new Child;
$child->echo_var();
}
}
class Child extends App {
public function __construct()
{
parent::__construct();
}
public function echo_var() {
echo $this->var;
}
}
$app = new App;
$app->load();
I find it very strange that your parent class instanciates it's child. Generally, you would instanciate the child, and you get all the functionality of the parent.
$app = new Child();
$app->load();
The problem is that you actually have 2 different instanciations. You have an object of App and it's holding a separate object of Child.
The other way to do this would be to make $var a static variable and then it would be available independent of the instantiation. I don't generally recommend making properties static though. It's generally considered bad form (for numerous reasons).
I'm using WordPress as a CMS, and I want to extend one of its classes without having to inherit from another class; i.e. I simply want to "add" more methods to that class:
class A {
function do_a() {
echo 'a';
}
}
then:
function insert_this_function_into_class_A() {
echo 'b';
}
(some way of inserting the latter into A class)
and:
A::insert_this_function_into_class_A(); # b
Is this even possible in tenacious PHP?
If you only need to access the Public API of the class, you can use a Decorator:
class SomeClassDecorator
{
protected $_instance;
public function myMethod() {
return strtoupper( $this->_instance->someMethod() );
}
public function __construct(SomeClass $instance) {
$this->_instance = $instance;
}
public function __call($method, $args) {
return call_user_func_array(array($this->_instance, $method), $args);
}
public function __get($key) {
return $this->_instance->$key;
}
public function __set($key, $val) {
return $this->_instance->$key = $val;
}
// can implement additional (magic) methods here ...
}
Then wrap the instance of SomeClass:
$decorator = new SomeClassDecorator(new SomeClass);
$decorator->foo = 'bar'; // sets $foo in SomeClass instance
echo $decorator->foo; // returns 'bar'
echo $decorator->someMethod(); // forwards call to SomeClass instance
echo $decorator->myMethod(); // calls my custom methods in Decorator
If you need to have access to the protected API, you have to use inheritance. If you need to access the private API, you have to modify the class files. While the inheritance approach is fine, modifiying the class files might get you into trouble when updating (you will lose any patches made). But both is more feasible than using runkit.
An updated way for 2014 that copes with scope.
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
Eg:
class stdObject {
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
}
$obj = new stdObject();
$obj->test = function() {
echo "<pre>" . print_r($this, true) . "</pre>";
};
$obj->test();
You can use the runkit extension for this, but you should really consider regular inheritance instead.
See runkit_method_add.
No you can't dynamically change a class during runtime in PHP.
You can accomplish this by either extending the class using regular inheritance:
class Fancy extends NotSoFancy
{
public function whatMakesItFancy() //can also be private/protected of course
{
//
}
}
Or you could edit the Wordpress source files.
I'd prefer the inheritance way. It's a lot easier to handle in the long run.