I've experimented with Late Static Bindings and tried different combinations of using self :: and static :: and then got something really strange. I do not understand how it is possible that the script executes without any warning (error_reporting = E_ALL). Could anyone try to explain how that works?
class A {
private function privateWho() {
echo __CLASS__.PHP_EOL;
}
public function test() {
B::privateWho();
}
}
class B extends A {}
$b = new B();
$b->test(); // prints A
Related
So I came across a code like this and it makes use of one of the Bar class properties called testObj while it's not defined so I expected this to be wrong but I tested it my own and no errors:
<?php
class Foo{
public function __construct()
{
echo 'Echo From Foo';
}
}
class Bar{
public function __construct(Foo $foo)
{
$this->testObj = $foo;
}
}
$bar = new Bar(new Foo);
Why is that so? Does this have anything to do with the "Dynamic/Loose Type"ness of PHP or something else?
Properties can be defined dynamically and their visibility is defaulted to public as can be seen in the example below:
class X {
public function test()
{
$this->y = 'test';
}
}
$x = new X();
$x->test();
echo $x->y; // test
You can also do this without being in the class, so if I wanted to add another property, I could just do the following:
class X {
public function test()
{
$this->y = 'test';
}
}
$x = new X();
$x->test();
echo $x->y; // test
$x->z = 'blah';
echo $x->z; // blah
Remember, when a class in instantized it is just an object which can be manipulated as any other object.
Note: If I don't call test() in the above code, it will result it an error (undefined property) because the variable has not been defined except in the test() function.
Live Example
Repl
This is perfectly normal, you can dynamicaly assign every propteries to a PHP class without error. Event if you should declare it properly to keep track of your object structure.
If you want it to throw an error, you can use the __get magic function and ReflectionClass to determine wich property is setted and wich you can't set even if I didn't see any advantage of doing this.
I have some confusion with __call() and everything I search about it tells me it should work
<?php
class A {
abstract public function C();
private function B(){
echo "B";
}
public function __call($method,$arguments){
if(method_exists("C", $method)) {
$this->B();
return call_user_func_array(array("C",$method),$arguments);
}
}
}
class B extends A{
public function C(){
echo "C";
}
}
$b = new B();
$b->C();
//the result I get:
// C
//the result I want;
// BC
?>
So, what I want as result is that I call function C but B get's echo'd out first. It worked at some point even, I am just really confused at what is going on. The php manual isn't that clear about it either, at least not what I am trying to do.
note: The most confusing is, the above __call method is not reponsive anymore, if I do a test message in there, doesn't print it.
As said, I've got it to work at some magical moment. Can someone point me to what I am doing wrong, or is it possible? ( I have changed some stuff over time, so that might have changed the scenario.
I think you're confusing what __call does. It's for inaccessible methods. So let's take A
class A {
abstract public function C();
private function B(){
echo "B";
}
public function __call($method,$arguments){
if(method_exists("C", $method)) {
$this->B();
return call_user_func_array(array("C",$method),$arguments);
}
}
}
Now, your B() is private but C() in your child is not
class B extends A{
public function C(){
echo "C";
}
}
The problem is your code never touches B() the method. You're calling B() the class
$b = new B();
$b->C();
To get __call to work you need to do
$b = new B();
$b->B(); // invokes __call()
__call() is only invoked when the function isn't specified/accessible --
See: http://us2.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
You cannot do what you are attempting to do.
I have the following class, and for some reason it's not accessing the test property. Why is this? I'm new to OOP, so please be easy on me. Thanks
class Test {
private $test;
function __contruct() {
$this->test = "test";
}
static function test() {
echo $this->test;
}
}
$test = new Test;
$test::test();
Because static methods are callable without an instance of the object
created, the pseudo-variable $this is not available inside the method
declared as static.
PHP Documentations.
Good morning.
It seems you have 3 issues with your code.
There is a syntax error at constructor line change it from __contruct to __construct.
Change test function visibility to public
Access your function with the -> instead of ::
To elaborate further on the above answers: Static methods and variables are not linked to any particular instance of the object, this is why you have to call test with $test::test(). This also means that you cannot access an instance variable from without a static method and it doesn't really make sense to do so (If you had multiple instances of the object with different values set for that variable, how would the interpreter know which instance/value to use?)
If you want to have a field accessible from a static method then you have to make the field static as well. So, if you wanted to have $test accessible from your static method test() then you'd have to write your function as something along these lines:
class Test {
private static $test;
function __contruct() {
Test::$test = "test";
}
public function test() {
echo Test::$test;
}
}
$test = new Test;
$test::test();
However, it doesn't really make sense to be initialising a static field like that in your constructor. So you'd more likely be wanting to do something like:
class Test {
private static $test = "test";
function __contruct() {
}
public static function test() {
echo Test::$test;
}
}
$test = new Test;
$test::test();
Or, if you don't actually require test() to be static then you could just make it an instance method:
class Test {
private $test = "test";
function __contruct() {
$this->$test = "test"
}
public function test() {
echo $this->$test;
}
}
$test = new Test;
$test->test();
This question already has answers here:
Use global variables in a class
(4 answers)
Closed 10 years ago.
I'm starting with OOP in PHP and there is something I'd like to do. Let me show an example:
classes.php
<?php
class a {
public function a() {
echo 'a';
}
}
class b {
public function calla() {
$x->a();
}
}
?>
index.php
<?php
include('classes.php');
$x = new a();
$d = new b();
$d->calla();
?>
Is this possible? I know I can do something like:
class b {
public function calla($object) {
$object->a();
}
}
and
$d->calla($x);
but is the first example possible to do?
So you want to use $x as global variable? Syntax is the same, object or not:
class b {
public function calla() {
$GLOBALS['x']->a();
}
}
... or:
class b {
public function calla() {
global $x;
$x->a();
}
}
Of course, it's a horrible design that injects hard to track dependencies and will probably lead to unexpected side effects and head-scratching.
Additionally, a() is a poor method name for class a because it's the PHP 4 syntax for constructors. If you run this code:
<?php
class a {
public function a() {
echo 'a';
}
}
class b {
public function calla() {
$GLOBALS['x']->a();
}
}
$x = new a();
$d = new b();
$d->calla();
... you'll see that a() runs twice. Guess why?
I think I understand what you're trying to ask but you're mixing up parameters visibility concept with object passing in class methods. So let's clean up...
In your classes.php file the method calla() of the class b as absolutely nothing to do with class a, unless $x itself is an instance of the class a.
In your index.php file you instantiate $x as class a, but it is a global variable, and the class b has no visibility on it. Moreover, your call to $d->calla() would return an error because you are accessing a private method from outside.
Your third example gets closer to the solution, passing the instance to the calla() method helps class b seing the instance of class a, I guess you want to edit your index.php file to:
<?php
include('class.php');
$x = new a();
$d = new b();
$d->calla($x);
?>
But this still won't work until you change the private methods to public ones.
I am converting a PHP 5.3 library to work on PHP 5.2. The main thing standing in my way is the use of late static binding like return new static($options); , if I convert this to return new self($options) will I get the same results?
What is the difference between new self and new static?
will I get the same results?
Not really. I don't know of a workaround for PHP 5.2, though.
What is the difference between new self and new static?
self refers to the same class in which the new keyword is actually written.
static, in PHP 5.3's late static bindings, refers to whatever class in the hierarchy you called the method on.
In the following example, B inherits both methods from A. The self invocation is bound to A because it's defined in A's implementation of the first method, whereas static is bound to the called class (also see get_called_class()).
class A {
public static function get_self() {
return new self();
}
public static function get_static() {
return new static();
}
}
class B extends A {}
echo get_class(B::get_self()); // A
echo get_class(B::get_static()); // B
echo get_class(A::get_self()); // A
echo get_class(A::get_static()); // A
If the method of this code is not static, you can get a work-around in 5.2 by using get_class($this).
class A {
public function create1() {
$class = get_class($this);
return new $class();
}
public function create2() {
return new static();
}
}
class B extends A {
}
$b = new B();
var_dump(get_class($b->create1()), get_class($b->create2()));
The results:
string(1) "B"
string(1) "B"
In addition to others' answers :
static:: will be computed using runtime information.
That means you can't use static:: in a class property because properties values :
Must be able to be evaluated at compile time and must not depend on run-time information.
class Foo {
public $name = static::class;
}
$Foo = new Foo;
echo $Foo->name; // Fatal error
Using self::
class Foo {
public $name = self::class;
}
$Foo = new Foo;
echo $Foo->name; // Foo
Please note that the Fatal error comment in the code i made doesn't indicate where the error happened, the error happened earlier before the object was instantiated as #Grapestain mentioned in the comments