I am trying to save an object as property in an another class, PHP throwing notices and fatal errors. Simplified version of my code:
<?php
class A {
public function a() {
// do something
}
}
$A = new A();
class B {
private $A;
public function __constructor($A) {
$this->A = $A;
}
private function b() {
if($this->A->a()) { // This line is referred by PHP
// do something
}
}
}
$B = new B($A);
You have a typo. Change __constructor to __construct and PHP will process your code correctly. Constructors in PHP are always named __construct. See the documentation for more details.
Related
I cannot seem to call a function from a function within a class. I've created some helper functions to help me do math on the current object but I can't seem to access any functions, even if they are defined and called in the same class.
I've tried using: $this->b(); I have also tried self::b(); from within the a() function but I get the same error everytime.
Fatal error: Uncaught Error: Call to undefined function b()
class test{
function a(){
$a = b();
return $a;
}
function b(){
return 'testing';
}
}
when I call the class function using:
$obj = new test();
$value = $obj::a();
echo $value;
I do not receive anything back but an error saying the function does not exist.
I just need to access functions from within a class, I don't know what else to try this is very easy in a lot of other programming languages, what am I missing? Thanks
To call a method in the same class as the calling method use $this->
If the class is instantiated and not static you also use -> and not the ::
See annotations for changes
class test{
function a(){
$a = $this->b(); // changed
return $a;
}
function b(){
return 'testing';
}
}
$obj = new test();
$value = $obj->a(); // changed
echo $value;
Tested Result:
testing
If you wanted the class to be static as it appears from the code change you made in your question then this is the way
class test{
static function a(){
$a = self::b();
return $a;
}
static function b(){
return 'testing';
}
}
//$obj = new test();
//$value = $obj::a();
$value = test::a();
echo $value;
Also tested result
testing
<?php
class a{
public function out(){
$this->test = 8;
return $this->test;
}
}
$b = new a();
echo $b->out();
?>
output: 8
when i run this code, output the result 8 .
but when i add __set() function, it output a notice, and not 8 output
<?php
class a{
public function __set($property, $value) {
}
public function out(){
$this->test = 8;
return $this->test;
}
}
$b = new a();
echo $b->out();
?>
output:
PHP Notice: Undefined property: a::$test in /usercode/file.php on line
13
why is it happening?
As per the docs
__set() is run when writing data to inaccessible properties.
Since you do not have anything in your __set body, the property is not created and therefore not available. You have to define the method body.
class a{
public function __set($property, $value) {
$this->$property = $value;
}
public function out(){
$this->test = 8;
return $this->test;
}
}
$b = new a();
echo $b->out();
Now THAT outputs 8.
Update
You are asking why the first block of code works and the second does not. Take a look at PHP source code here and you will see the explanation in the code itself.
Looks to me, that when you do not have __set() in your class and you do $this->test, PHP internally calls it's own __set(), which does exactly what it does: sets the property name to certain value.
But when you define __set() with empty body, it overrides the default internal __set() and does nothing. And that is the main reason for your code to fail - the requested property has not been set neither by your __set(), nor by the internal one.
When a::out() runs, there is no $test property in the object. This is why $this->test = 8; invokes a::__set().
But a::__set() doesn't create the $test property and the next statement (return $this->test;) cannot find it and produces the notice.
You should declare the object properties in the class definition and initialize them in the constructor (if appropriate):
class a {
private $test; // <-- because of this, $this->test exists...
public function __set($property, $value) {
}
public function out() {
$this->test = 8; // ... and __set() is not invoked here
return $this->test;
}
}
Without __set() being defined, the statement $this->test = 8; creates the $test property of the current object if it is not already created (by its definition or by a previous assignment to it) then stores 8 into it.
When __set() is defined, any attempt to set a property that doesn't exist or it is not accessible (setting inside the class a private property inherited from the parent class or setting a protected or private property outside the class) is handled by __set(). Your implementation of __set() doesn't create the missing property and it basically turns the statement $this->test = 8; into a no-op.
The following is true.
<?php
class a{
public function __set($property, $value) {
$this->$property = $value;
}
public function out(){
$this->test = 8;
return $this->test;
}
}
$b = new a();
echo $b->out();
you should look at is php overloading
Find the answers in the manual.
PHP 5.4.5, here. I'm trying to invoke an object which is stored as a member of some other object. Like this (very roughly)
class A {
function __invoke () { ... }
}
class B {
private a = new A();
...
$this->a(); <-- runtime error here
}
This produces a runtime error, of course, because there's no method called a. But if I write the call like this:
($this->a)();
then I get a syntax error.
Of course, I can write
$this->a->__invoke();
but that seems intolerably ugly, and rather undermines the point of functors. I was just wondering if there is a better (or official) way.
There's three ways:
Directly calling __invoke, which you already mentioned:
$this->a->__invoke();
By assigning to a variable:
$a = $this->a;
$a();
By using call_user_func:
call_user_func($this->a);
The last one is probably what you are looking for. It has the benefit that it works with any callable.
FYI in PHP 7+ parenthesis around a callback inside an object works now:
class foo {
public function __construct() {
$this -> bar = function() {
echo "bar!" . PHP_EOL;
};
}
public function __invoke() {
echo "invoke!" . PHP_EOL;
}
}
(new foo)();
$f = new foo;
($f -> bar)();
Result:
invoke!
bar!
I know this is a late answer, but use a combination of __call() in the parent and __invoke() in the subclass:
class A {
function __invoke ($msg) {
print $msg;
}
}
class B {
private $a;
public function __construct() { $this->a = new A(); }
function __call($name, $args)
{
if (property_exists($this, $name))
{
$prop = $this->$name;
if (is_callable($prop))
{
return call_user_func_array($prop, $args);
}
}
}
}
Then you should be able to achieve the syntactic sugar you are looking for:
$b = new B();
$b->a("Hello World\n");
I've got the following issue
class class_name {
function b() {
// do something
}
function c() {
function a() {
// call function b();
}
}
}
When I call function as usual: $this->b(); I get this error: Using $this when not in object context in C:...
function b() is declared as public
any thoughts?
I'll appreciate any help
Thanks
The function a() is declared inside method c().
<?php
class class_name {
function b() {
echo 'test';
}
function c() {
}
function a() {
$this->b();
}
}
$c = new class_name;
$c->a(); // Outputs "test" from the "echo 'test';" call above.
Example using a function inside a method (not recommended)
The reason why your original code wasn't working is because of scope of variables. $this is only available within the instance of the class. The function a() is not longer part of it so the only way to solve the problem is to pass the instance as a variable to the class.
<?php
class class_name {
function b() {
echo 'test';
}
function c() {
// This function belongs inside method "c". It accepts a single parameter which is meant to be an instance of "class_name".
function a($that) {
$that->b();
}
// Call the "a" function and pass an instance of "$this" by reference.
a(&$this);
}
}
$c = new class_name;
$c->c(); // Outputs "test" from the "echo 'test';" call above.
class Fruit {
protected $blend;
public function WillItBlend() {
return $this->blend;
}
public static function MakeFruit() {
$objF = new Fruit();
$objF->blend = true;
return $objF;
}
}
$fruit = Fruit::MakeFruit();
echo $fruit->WillItBlend();
Why is this line working $objF->blend = true; instead of throwing a Fatal error ?
The visibility modifiers work at the class level, not at the object level. This also means that objects of the same class can access each other's private bits.
An example at the PHP interactive prompt:
php > class Foo {
private $bar;
public function __construct() { $this->bar = rand(1, 100); }
public function baz($another_foo) { echo $another_foo->bar, '-', $this->bar; }
}
php > $a = new Foo();
php > $b = new Foo();
php > $a->baz($b);
86-70
$objF is instance of class Fruit.
$objF->blend is being used in class itself. Protected properties can be used in class itself.
You will get Fatal Error if you use it outside the class as $fruit->blend;
So it is allowed to do so.
because you're accessing it from inside the class, if you would call from outside the class
$fruit = Fruit::MakeFruit();
echo $fruit->WillItBlend();
echo $fruit->blend;
it would throw a fatal error.