Instantiating classes and accessing methods from different classes - php

I'm trying to use a Class_B function in one of Class_A's functions. But a lot of Class_B's functions include $this which causes problems. These are both classes (each class is of course in its own file):
class Class_A
{
function hello()
{
require('class_b.php');
echo 'Hello ' . Class_B::person();
}
function bye()
{
require('class_b.php');
echo 'Bye ' . Class_B::person();
}
}
class Class_B
{
function person()
{
// various operations and variables
echo $this->get_user($id);
}
}
When I run the Class_A file I get Call to undefined method Class_A::person() in (...) because I think the $this value is changed when I instantiate the Class_A class. It overrules the Class_B value. How can I stop this?
Also, another question: how can I access Class_B from every function in Class_A? I don't want to redeclare the class. Do I need to do this:
class Class_A
{
function function1()
{
require('class_b.php');
$class_b = new Class_B();
// code
}
function function2()
{
require('class_b.php');
$class_b = new Class_B();
// code
}
}
Or do I need to use a constructor or something?

By Class_B::person() you are calling the method statically. So you should declare the person() method as static and can't use $this because you don't have an instance of Class_B.
If you need an instance of Class_B, just create it and store in the class_B on construction.
class Class_A {
private $b;
function __construct()
{
$this->b = new Class_B();
}
function stuff()
{
$this->b->person();
}

Don't put require inside a method. Code in an included file inherits the scope of the place where you include it, and in your example, bad things happen. Also, for class definition scripts, consider require_once instead of require, to avoid multiple definitions.
As a rule of thumb, put all includes and requires at the top of your script. Better yet, set up a class autoloader, and register it in an auto_prepend script. That way, you won't have to manually include anything at all (at least not for class definitions).

What you might want is dependency injection, whereby you pass an object of Class_B into Class_A's constructor and hold it as a property in Class_A. It then becomes available in Class_A as $this->classB or similar.
// Include Class_B code outside the class.
require_once('class_b.php');
class Class_A {
// Property to hold Class_B
public $b;
// Constructor
public function __construct($b) {
$this->b = $b;
}
public function function1(){
// code
$this->b;
}
public function function2(){
// code
$this->b;
}
}
// Now call your objects:
// The Class_B which will be injected into A
$b = new Class_B();
// Your Class_A, which holds an instance of Class_B as a property
$a = new A($b);

Related

When can $this reference variables outside its class in PHP?

class A {
public function f(){
$this->ar[0] = 'something';
}
}
For example, how can function f be called such that $this->ar will refer to an array declared outside of class A? Assume that A is not inheriting ar.
Edit:
I tried to simplify the question. The actual code I'm looking at is
the function index in opencart's ControllerStartupStartup class
The function index is using $this to access class instances that aren't defined in that class: $this->db,$this->config, and $this->tax.
They are not declared in the parent class Controller either.
The function is being called with call_user_func_array(array($controller, $this->method), $args); in the Action class.
Maybe you can make "ar" known and provide it in the class as setter, so the instance ar is known and you can address it with $this
class A {
$ar = array();
public function f(){
$this->ar[0] = 'something';
}
}
// INSTANCE with Setter
$ar[0]='whatever';
$class = new A();
$class->ar = &$ar;
$class->f();
echo $ar[0];

PHP: Extending Classes

I'm absolutely sure this has been asked before, but I cannot find it anywhere.
So I have two classes. A and B
class classA
{
public $var1;
public $classbVar;
public function init()
{
// This is here because other script is run before it is called
// in the live code.
// it basically checks that the file exists. There is a reason for this.
if (file_exists('classB.php'))
{
require_once('classB.php');
}
else
{
echo "An error has occurred loading the second class.";
}
$this->var1 = "something";
$this->classbVar = new classB
echo $this->classbVar->doSomething();
}
}
In a separate file
class classB extends classA
{
public function doSomething()
{
echo $this->var1;
}
}
In a third file, I'm calling classA and running the init function. This is not real code, but identical to what I have written.
So why doesn't this work. if I VAR_DUMP I get null.... What have I done wrong or misunderstood?
LET ME BE MORE CLEAR:
There is a third file which calls classA as below;
require_once('classA.php')
$classA = new classA;
$classA->init();
My apologies for any confusion, I did this on the fly a little bit, as I am sure I am missing something simple here. Surely the way I am trying to do this will work somehow.
There are 2 problems here that cause your output to be null:
You are generating a new $classA object and any values you set on that, will not automatically be set on the $classbVar object as that is a completely different object of a class that just extends the A class, not the $classA object you have just generated. With the exception of a static property of course...
If you want to set the value of a property in an object, you need $this->var1 instead of $var1. Note if you set the value in your $classA object, it is still not set for the $classbVar object.
Put require_once above class declaration (this is not big issue but it's more clear)
Assign variables to class properties because they way you did the scope of them is only within the method.
$var1 = "something";
should be changed to
$this->var1 = "something";
Also the class values are not shared unless they are declared as static. So to access the properties from parent class you can do following:
class classA
{
public $var1;
public function init()
{
$this->var1 = "something";
}
}
// other file
require_once("A class location");
class classB extends classA
{
public function doSomething()
{
echo $this->var1;
}
}
$b = new classB();
$b->init();
$b->doSomething();
or more clean way:
class A
{
protected $var1;
public function __construct()
{
$this->var1 = "something";
}
}
// other file
require_once("A class location");
class B extends A
{
public function doSomething()
{
return $this->var1;
}
}
$b = new B();
echo $b->doSomething();
// or shorter syntax
echo {new B()}->doSomething();
Instead of using require_once() it's better to use PSR-4 autoloader.

PHP Classes calling functions to it

I saw some codes that when they call php functions from another class they no longer use $this->functionName(),
they just refer immedietly to the function name, like functionName()
In my index.php
$help = new Helper();
$help->Test();
I wanted to call Test Function by not doing the $help.
How can this be done? Why is this possible?
In PHP you can mix a procedural style of programming with object oriented style. That means that function can either exist as member of a class, or as stand-alone functions.
Member functions (or methods) are are called using $classinstance->methodname() for normal (instance) methods, or ClassName::methodName() for static methods.
Standalone functions are just called without referring to a class or object whatsoever. You can put them in separate files, if you like.
The declaration and usage is as follows:
In example.php:
class MyClass
{
$member = 'Hello world';
function MyMethod()
{
// The method can use the instance variable (member variable)
// using $this to refer to the instance of the class
echo $this->member;
}
static function MyStaticMethod()
{
echo 'Hello static world';
}
}
function MyFunction()
{
echo 'Hello';
}
In index.php:
// To include the class and its methods, as well as the function.
require_once 'example.php';
// Call an instance method
$instance = new MyClass();
$instance->MyMethod();
// Call a static method
MyClass::MyStaticMethod();
// Call a stand-alone function
MyFunction();
A standalone function is defined like this:
function myfunction() {
# whatever
}
Also see http://www.php.net/manual/en/functions.user-defined.php
With the -> operator you reference a function from within a class.
<?php
class A {
public function a() {
$this->b(); //references the function b() in $this class
}
public function b() {
echo 'Was called from function a() in class A';
}
}
function c() {
echo "I'm just a simple function outside a class";
}
//now you can do following calls
$class_a = new A();
$class_a->a();
c(); //references function c() within the same scope
The output would be:
Was called from function a() in class A
I'm just a simple function outside a class
But you could also do the following: outsource the function c() into an external file like function_c.php
Now, you can include/require the file from anywhere else and use it's content:
include 'function_c.php';
c(); //the function is now available, although it was defined in another file
you can a function from another class from a class, example:
require "myExternClass.php";
class myClass extends myExternClass
{
public function a() {
$this->b(); /* function b is in the class myExternClass */
}
}
generally you can't call a method of an object without the object itself.
but for some cases when method does not actually uses any objects' properties it may be acceptable for testing purposes to invoke it with call_user_func_array, passing some dummy value instead of object.
class A {
var $a;
function doNop() { echo "Nop";}
function doA() { echo "[".$a."]"; }
}
// instead of this
$a = new A;
$a->doNop();
// you _may_ use this
A::doNop();
// but this will fail, because there's no object to apply doA() to.
A::doA();
class A_dummy { $a };
// however, for testing purposes you can provide a dummy instead of real A instance
$b = new A_dummy;
call_user_func(array($b, 'A::doA'));
You can wrap the code in question inside a regular function:
function TestClass() {
$help = new Helper();
return $help->Test();
}
Then, in your index.php file you can call the function like this:
TestClass();

require_once() in a class

I noticed that if I declare a function inside a class method that has the same name as a outside function I get a error:
function a(){
...
}
class foo{
public function init(){
function a(){ // <- error
...
}
...
}
}
this however would work:
function a(){
...
}
class foo{
public static function a(){
...
}
}
Can I include a set of functions that act as static methods for this class using require_once or something like that?
require_once('file.php'); after class foo{ doesn't work...
PHP allows to nest function declarations in others, but it doesn't actually have nested functions. They always end up in the global scope. So the a() that you define in your init method clashes with the already defined function a().
The static function a() is associated with the class namespace, even if it behaves like a function, not a method.
Invoking a require_once statement in a class definition is not possible. The PHP syntax does not allow for it. Class definitions are special scopes / language constructs, that only allow function or variable declarations within the immediate parsing level. - So PHP does not allow for that (classes and their methods must be declared at once, not assembled), and there are no really nice or advisable workarounds for what you want.
If your class structure allows, you can split the class into several different classes which are part of an inheritance chain:
class foo1 {
public static function a() {}
}
class foo extends foo1 {
public static function b() {}
}
Alternatively, you can use __callStatic() if you are willing to take the performance hit. (Requires PHP 5.3; though if you only need non-static methods, __call is available from 5.0.) Smarty 3 does this IIRC.
class foo {
private static $parts = array('A', 'B');
public static __callStatic($name, $arguments) {
foreach (self::$parts as $part) {
if (method_exists($part, $name)) {
return call_user_func_array(array($part, $name), $arguments);
}
}
throw new Exception();
}
}
class A {
public static function a() {}
}
class B {
public static function b() {}
}
PHP 5.4 will supposedly include traits, which are a more straightforward way of including external code in a class:
class foo {
use A, B;
}
trait A {
public static function a() {}
}
trait B {
public static function b() {}
}
To answer the question: you should first check whether or not the function a has already been implemented by using function_exists:
class foo{
public function init(){
if(!function_exists('a')):
function a(){ // <- will only be declared when it doesn't already exist
...
}
endif;
...
}
}
However, consider this as a very bad coding practice. It will get a mess pretty soon as you have no idea of what's going on exactly and what function will be used. I'd say you'd be better off using a subclass and require_once the appropriate subclass.
Assuming not defining the second "a" method is not acceptable, you'll need to move it outside the init method.
It sounds like your require_once call is the problem (definitely should not be called inside the class). Could you post a full sample including your require_once call that isn't working ?

call a static method inside a class?

how do i call a static method from another method inside the same class?
$this->staticMethod();
or
$this::staticMethod();
self::staticMethod();
More information about the Static keyword.
Let's assume this is your class:
class Test
{
private $baz = 1;
public function foo() { ... }
public function bar()
{
printf("baz = %d\n", $this->baz);
}
public static function staticMethod() { echo "static method\n"; }
}
From within the foo() method, let's look at the different options:
$this->staticMethod();
So that calls staticMethod() as an instance method, right? It does not. This is because the method is declared as public static the interpreter will call it as a static method, so it will work as expected. It could be argued that doing so makes it less obvious from the code that a static method call is taking place.
$this::staticMethod();
Since PHP 5.3 you can use $var::method() to mean <class-of-$var>::; this is quite convenient, though the above use-case is still quite unconventional. So that brings us to the most common way of calling a static method:
self::staticMethod();
Now, before you start thinking that the :: is the static call operator, let me give you another example:
self::bar();
This will print baz = 1, which means that $this->bar() and self::bar() do exactly the same thing; that's because :: is just a scope resolution operator. It's there to make parent::, self:: and static:: work and give you access to static variables; how a method is called depends on its signature and how the caller was called.
To see all of this in action, see this 3v4l.org output.
This is a very late response, but adds some detail on the previous answers
When it comes to calling static methods in PHP from another static method on the same class, it is important to differentiate between self and the class name.
Take for instance this code:
class static_test_class {
public static function test() {
echo "Original class\n";
}
public static function run($use_self) {
if($use_self) {
self::test();
} else {
$class = get_called_class();
$class::test();
}
}
}
class extended_static_test_class extends static_test_class {
public static function test() {
echo "Extended class\n";
}
}
extended_static_test_class::run(true);
extended_static_test_class::run(false);
The output of this code is:
Original class
Extended class
This is because self refers to the class the code is in, rather than the class of the code it is being called from.
If you want to use a method defined on a class which inherits the original class, you need to use something like:
$class = get_called_class();
$class::function_name();
In the later PHP version self::staticMethod(); also will not work. It will throw the strict standard error.
In this case, we can create object of same class and call by object
here is the example
class Foo {
public function fun1() {
echo 'non-static';
}
public static function fun2() {
echo (new self)->fun1();
}
}
call a static method inside a class
className::staticFunctionName
example
ClassName::staticMethod();

Categories