I have some problems with my class Model and other classes so I made this simple example to explain my problem :
class person{
public static $a = "welcome";
public function __construct(){
}
public static function getobject()
{
$v = new person();
return $v;
}
}
class student extends person{
public static $b = "World";
}
$st = student:getobject();//this will return person object but I want student object
echo $st->$b; // There is an error here because the object is not student
So I want to know what to write instead $v = new person(); to get the object of the last inherited class.
Use the late static binding's static keyword.
public static function getobject()
{
$v = new static();
return $v;
}
So, with student::getobject() you get an instance of student.
To retrieve the static (but why?) $b propriety, you can do $st::$b, or simply student::$b.
Related
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
}
There is a property $modelName in class A that is accessed in this class using $this->modelName.
This property contains a name of another class B.
I want to call a static method of class B not creating an object of B.
Working code:
$b = $this->modelName;
$b::model()->findAll();
Question:
How to call model()->findAll() not using $b?
I tried $this->modelName::model()->findAll(); but it’s not working.
Do it:
class A{
public $modelName = 'B';
function callB(){
call_user_func(array($this->modelName, 'model'))->findAll();
}
}
class B{
private static $model = null;
static function model(){
if (!self::$model) {
self::$model = new B();
}
return self::$model;
}
function findAll(){
print __CLASS__.' method `findAll()`';
}
}
$A = new A;
$A->callB();
// B method `findAll()`
I have problem about calling a static property of a class inside another class.
Class A {
public $property;
public function __construct( $prop ) {
$this->property = $prop;
}
public function returnValue(){
return static::$this->property;
}
}
Class B extends A {
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
}
$B = new B( 'property_one' );
$B->returnValue();
I expect to return This is first property But the Output is just the name a parameter input in __construct;
When I print_r( static::$this->property ); the output is just property_one
Just change:
return static::$this->property;
with:
return static::${$this->property};
Maybe like this?
<?php
Class A {
public $property;
public function __construct( $prop ) {
$this->property = $prop;
print static::${$this->property};
}
}
Class B extends A {
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
}
$B = new B( 'property_one' );
(I mean you can access (print,...) the property this way, but the constructor will return an object anyway.)
There are several issues here:
the static property $property_one is declared in class B, the A class's constructor won't have access to that property, nor can you guarantee this property to be present.
Granted, since PHP 5.3, late static binding is supported, but that doesn't change the fact that you're never going to be sure that some static property that just happens to be called whatever $this->property happens to be assigned. What if it's assigned an object? an int, or float?
You access a static property like this: static::$propery or self::$property. Note the $! When you write static::$this->property, you're expecting this to evaluate to self::property_one. You're clearly missing the $ sign.
The very least you need is self::${$this->property}. Check the PHP manual on variable variables.
You're attempting to return a string from a constructor function, that's not possible. A constructor must, must return an instance of the class. Any return statements that don't will be ignored.
To have access to a static property of a child class in the constructor, you can't but rely on the child's constructor:
Class A
{
public $property;
}
Class B extends A
{
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
public function __construct( $prop )
{
$this->property = $prop;
print self::${$this->property};
}
}
$B = new B( 'property_one' );
An alternative would be:
Class A
{
public $property;
public function __constructor($prop)
{
$this->property = $prop;
}
public function getProp()
{
return static::${$this->property};
}
}
Class B extends A
{
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
}
$B = new B( 'property_one' );
$B->getProp();
class parents{
public $a;
function __construct(){
echo $this->a;
}
}
class child extends parents{
function __construct(){
$this->a = 1;
parent::__construct();
}
}
$new = new child();//print 1
This code above print 1,which means whenever we create an instance of a child class,and assign value to properties inherited from its parent,the property in its parent class also has been assigned.But the code below shows different:
class parents{
public $a;
function test(){
$child = new child();
echo $this->a;
}
}
class child extends parents{
function __construct(){
$this->a = 1;
}
}
$new = new parents();
$new->test();//print nothing
Where I assign value to its child class and the parent apprently didn't have the value it assigned to its child class,why?
Thanks!
In the top example, since the construct function is being called from the child class, it is treating the object being used as if it were the child object that is just using a function in the parent class as if it were it's own.
In the bottom example you have two separate objects acting independently. The parent object has it's $a and so does the child, but they are not the same $a since they are contained in separate objects. so when you print $this->a in the parent class, it is referring to the parent's instance of $a whereas if you echo $a after setting $this->a =1 in the child class it would display the child's instance of $a.
Hope this cleared some stuff up for you.
You are mixing object composition and class inheritance.
Inheritance (realized through the extends keyword) defines an is a relationship.
Composition defines a has a relationship.
To illustrate this concept we will start with inheritance.
class Person {
public $name;
public function talk(){};
public function poop(){};
}
class Parent extends Person {
public function __construct($name) {
$this->name = $name;
}
}
class Child extends Person {
public function __construct($name){
$this->name = $name;
}
}
In this example we are defining a class of things called People. From that definition we are deriving two different subtypes of People, Parent and Child. When we subtype a class then the subtype gains it's own copy of all of the properties and has access to all of the methods defined in the base type, so without defining it a Child and Parent have a name and can both talk and poop by virtue of also being a person.
For example:
$parent = new Parent("Homer");
$child = new Child("Bart");
$parent->talk();
$child->poop();
Composition is used when you want to implement a has a relation ship. Lets revise our type definition of Parent.
class Parent extends Person {
public $children = array();
public function __construct($name) {
$this->name = $name;
}
public function addChild(Child $child){
$this->children[] = $child;
}
}
What we have now allowing if for a Parent to have a child.
$parent = new Parent("Homer");
$child = new Child("Bart");
$parent->addChild($child);
// now I can access homers first child
echo $parent->children[0]->name;
When you instantiate parent, the instance of child created extends the parent class with to test() function. However, that doesn't change the value of $a.
That happens, because you have two different instances, which have nothing in common(except the the inheritance..)
The behavior you except could be generated with inner classes - which php don't support.
If you want to share an var accros every instance, you have to make it static
class parents{
public static $a;
function test(){
$child = new child();
echo self::$a;
}
}
class child extends parents{
function __construct(){
self::$a = 1;
}
}
$new = new parents();
$new->test();
which isn't probably what you want. Or you tell exactly, where you want to change your var
class parents{
public $a;
function test(){
$child = new child();
echo $child->a;
}
}
class child extends parents{
function __construct(){
$this->a = 1;
}
}
$new = new parents();
$new->test();
It's because in the first example you instantiate child
$new = new child();//print 1
and in the second you instantiate parents
$new = new parents();
The second works the same as the first using $new = new child();
If you want to access $a by instantiating child() you need to do it like this:
class parents{
public $a;
function test(){
$child = new child(); //CHANGE HERE
echo $child->a;
}
}
class child extends parents{
function __construct(){
$this->a = 1;
}
}
$new = new parents();
$new->test();
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