Checking if variable exists for child class - php

I'm creating global setters and getters for my parent class since I don't want to create them for each child class variable (but I will occasionally overwrite the parent global setter / getter).
I'm using __call with it and I'm parsing the method name like this:
if (strtolower(substr($method, 0, 3)) == "set") {
$variable = strtolower(substr($method, 3));
}
The question is how can I check if the $variable is set for the child class (the one that is extending the main one);
If I do:
if ($this->$variable)
I suppose it first check if it exists on the child class and then it checks if it exists on the main class. I want it only to check the child class, is this possible to do?
I know there's parent:: but is there an equivalent for child?
EDIT:
People are not understanding what I'm asking.
I know how to check if the property exists. What I want to know is how to check if the property exists for the CHILD class, not for the MAIN class.
(class CHILD extends MAIN)

In common case there's isset() function, but is will not fit this case. Use property_exists() instead:
class Foo
{
public $pub = null;
}
$obj = new Foo();
var_dump(isset($obj->pub), property_exists('Foo', 'pub')); //false, true
-that's because if proprty exists, but is null, isset() will return false - and you'll not be able to differ the case, when it does not exist.
If it's about dynamic properties - then you should pass object and not class name to property_exists() since property may absent in class and then dynamically added to object.
Now, if we're saying about which class is declaring property, you can use Reflection in PHP, like this:
class Foo
{
public $pub = null;
}
class Bar extends Foo
{
}
$obj = new Bar();
$ref = new ReflectionObject($obj);
var_dump($ref->getProperty('pub')->getDeclaringClass()->getName() == 'Bar');//false
var_dump($ref->getProperty('pub')->getDeclaringClass()->getName() == 'Foo');//true

Why don't you make use of isset ??
if (isset($this->$variable))

This works for me:
if(property_exists($get_class($this),$variable)){}

Related

PHP setting property that doesn't exist in class works, why? how?

<?php
class ser {
public $a;
}
$x = new ser;
$x->b = 10;
var_dump($x);
Something like this.
Class ser has only $a property, but we can set $b to new object of this class and it works despite this class doesn't have any $b property
output
E:\XAMPP\htdocs\fun\test2.php:12:
object(kurde)[1]
public 'a' => null
public 'b' => int 10
Why this works?
Why we can add property and set it to this class while it doesn't belong exactly to this class?
How is that possible and why is that possible?
Any purpose? Sense of making this possible?
This is what PHP refers to as "overloading". This is different to overloading in almost any other object oriented language.
If you do not like it, you can use the __set magic method to throw an exception if a non-existent property is set:
public function __set($name, $value) {
throw new \Exception('Property "'.$name.'" does not exist')
}
You can tell from the comments on the documentation what the general consensus of this "feature" is.

php - setter of objects is not called

I have the following issue:
The current code of an application I'm working on contains a very large number of definitions like this:
$obj = new stdClass();
$obj->a->b = "something";
This results in: PHP Strict Standards: Creating default object from empty value in [somewhere].
The correct form would be:
$obj = new stdClass();
$obj->a = new stdClass();
$obj->a->b = "something";
Now the problem: Replacing this throughout the code would take ages (consider thousands of cases, with conditions, etc.).
So I was thinking of replacing stdClass with a custom object (this would be a simple replace in code), creating a setter for it that verifies if the variable property is an object, and defines it as object if it is before setting the second property.
So we get:
class MockObject() {
public function __set($property, $value) {
// Do stuff here
}
}
$obj = new MockObject();
$object->a->b = "something";
The problem is that when executing $object->a->b = "something"; setter is not called (because you don't actually set the a property, but the b property).
Is there any way around this? Or is other solution possible?
Note: Explicitly calling the __set() method is not a solution since it would be the same as defining properties as stdClass().
You know about the magic setter.
Use a magic getter also.
If it wants to get a var that does not exists: create one (in an array or something like that) that is an instance of that class.
Why don't you initialize your b variable in the constructor of the A class ?
public function __construct()
{
$this->b = new B();
}

Setting protected variable value in child class and accessing value in parent

I'm not sure if this is even possible but here goes. I want to set the value of a protected variable from within a child class and then access that value from the parent class. This is what I have tried:
class A {
protected $a;
public function __construct() {
new B;
echo "Parent Value: {$this->a}";
}
protected function setter($value) {
$this->a = $value;
}
}
class B extends A {
public function __construct() {
$this->setter('set value');
echo "Child Value: {$this->a}<br />";
}
}
new A;
I'm expecting the output for the above code to be:
Child Value: set value
Parent Value: set value
However I get the following instead:
Child Value: set value
Parent Value:
Is it possible to set the value of a protected variable from within a child class and then access that value in the parent class? If not how would I accomplish this?
You can set the value and access it from the child class without any problems - you are actually doing that when you generate your B-class object in the A-class constructor - but the problem with your code is that you are generating a parent object and in the constructor of that parent object you generate a new object of the child class.
So what is happening is:
You generate an A object, the constructor of the A class runs;
In the constructor you generate a B object. This is a new object, unrelated to your current A object;
The constructor of the B object you set the value and echo it (basically answering your own question), the first line of your output is as expected;
Continuing in the constructor of the A object, you discard the generated B-class object and echo the value of $this->a but that value is not set for that object, so you get nothing.
I am kind of confused why you would want to construct a child object in the constructor of the parent. Normally I would construct a B object and in the constructor of that object, first call the parent constructor before doing B-specific stuff.

PHP combine $this variable

How to combine two variables to obtain / create new variable?
public $show_diary = 'my';
private my_diary(){
return 1;
}
public view_diary(){
return ${"this->"}.$this->show_diary.{"_diary()"}; // 1
return $this->.{"$this->show_diary"}._diary() // 2
}
both return nothing.
Your class should be like following:
class Test
{
public $show_diary;
function __construct()
{
$this->show_diary = "my";
}
private function my_diary(){
return 707;
}
public function view_diary(){
echo $this->{$this->show_diary."_diary"}(); // 707
}
}
It almost looks from your question like you are asking about how to turn simple variables into objects and then how to have one object contain another one. I could be way off, but I hope not:
So, first off, what is the differnce between an object and a simple variable? An object is really a collection of (generally) at least one property, which is sort of like a variable within it, and very often functions which do things to the properties of the object. Basically an object is like a complex variable.
In PHP, we need to first declare the strucutre of the object, this is done via a class statement, where we basicaly put the skeleton of what the object will be into place. This is done by the class statement. However, at this point, it hasn't actually been created, it is just like a plan for it when it is created later.
The creation is done via a command like:
$someVariable= new diary();
This executes so create a new variable, and lays it out with the structure, properties and functions defined in the class statement.
From then on, you can access various properties or call functions within it.
class show_diary
{
public $owner;
public function __construct()
{
$this->owner='My';
}
}
class view_diary
{
public $owner;
public $foo;
public function __construct()
{
$this->foo='bar';
$this->owner=new show_diary();
}
}
$diary= new view_diary();
print_r($diary);
The code gives us two classes. One of the classes has an instance of the other class within it.
I have used constructors, which are a special type of function that is executed each time we create a new instance of a class - basically each time we declare a variable of that type, the __construct function is called.
When the $diary= new view_diary(); code is called, it creates an instance of the view_diary class, and in doing so, the first thing it does is assigns it's own foo property to have the value 'bar' in it. Then, it sets it's owner property to be an instance of show_diary which in turn then kicks off the __construct function within the new instance. That in turn assigns the owner property of the child item to have the value 'My'.
If you want to access single properties of the object, you can do so by the following syntax:
echo $diary->foo;
To access a property of an object inside the object, you simply add more arrows:
echo $diary->owner->owner;
Like this?
$diary = $this->show_diary . '_diary';
return $this->$diary();

Access class constant and static method from string

I have a string containing the class name and I wish to get a constant and call a (static) method from that class.
<?php
$myclass = 'b'; // My class I wish to use
$x = new x($myclass); // Create an instance of x
$response = $x->runMethod(); // Call "runMethod" which calls my desired method
// This is my class I use to access the other classes
class x {
private $myclass = NULL;
public function __construct ( $myclass ) {
if(is_string($myclass)) {
// Assuming the input has a valid class name
$this->myclass = $myclass;
}
}
public function runMethod() {
// Get the selected constant here
print $this->myclass::CONSTANT;
// Call the selected method here
return $this->myclass::method('input string');
}
}
// These are my class(es) I want to access
abstract class a {
const CONSTANT = 'this is my constant';
public static function method ( $str ) {
return $str;
}
}
class b extends a {
const CONSTANT = 'this is my new constant';
public static function method ( $str ) {
return 'this is my method, and this is my string: '. $str;
}
}
?>
As I expected (more or less), using $variable::CONSTANT or $variable::method(); doesn't work.
Before asking what I have tried; I've tried so many things I basically forgot.
What's the best approach to do this? Thanks in advance.
To access the constant, use constant():
constant( $this->myClass.'::CONSTANT' );
Be advised: If you are working with namespaces, you need to specifically add your namespace to the string even if you call constant() from the same namespace!
For the call, you'll have to use call_user_func():
call_user_func( array( $this->myclass, 'method' ) );
However: this is all not very efficient, so you might want to take another look at your object hierarchy design. There might be a better way to achieve the desired result, using inheritance etc.
in php 7 you can use this code
echo 'my class name'::$b;
or
#Uncomment this lines if you're the input($className and $constName) is safe.
$reg = '/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/';
if(preg_match($reg,$className) !== 1 || preg_match($reg,$constName) !== 1)
throw new \Exception('Oh, is it an attack?');
$value = eval("return $className::$constName;");
You can achieve it by setting a temporary variable. Not the most elegant way but it works.
public function runMethod() {
// Temporary variable
$myclass = $this->myclass;
// Get the selected constant here
print $myclass::CONSTANT;
// Call the selected method here
return $myclass::method('input string');
}
I guess it's to do with the ambiguity of the ::, at least that what the error message is hinting at (PHP Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM)
Use call_user_func to call static method:
call_user_func(array($className, $methodName), $parameter);
Classes defined as abstract may not be instantiated, and any class that contains at least one abstract method must also be abstract. Methods defined as abstract simply declare the method's signature - they cannot define the implementation.
When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child; additionally, these methods must be defined with the same (or a less restricted) visibility. For example, if the abstract method is defined as protected, the function implementation must be defined as either protected or public, but not private. Furthermore the signatures of the methods must match, i.e. the type hints and the number of required arguments must be the same. This also applies to constructors as of PHP 5.4. Before 5.4 constructor signatures could differ.
Refer to http://php.net/manual/en/language.oop5.abstract.php
This might just be tangential to the subject but, while searching for my own issue I found that the accepted answer pointed me in the right direction, so I wanted to share my problem & solution in case someone else might be stuck in a similar fashion.
I was using the PDO class and was building some error options from an ini config file. I needed them in an associative array in the form: PDO::OPTION_KEY => PDO::OPTION_VALUE, but it was of course failing because I was trying to build the array with just PDO::$key => PDO::$value.
The solution (inspired from the accepted answer):
$config['options'] += [constant('PDO::'.$key) => constant('PDO::'.$option)];
where everything works if you concatenate the class name and the Scope Resolution Operator as a string with the variable and get the constant value of the resulting string through the constant function (more here).
Thank you and I hope this helps someone else!

Categories