Is it possible to unset a static property in PHP? - php

I'm trying to use classes with static methods and properties instead of Singletons. Everything was ok until I had to unset a static property, and my PHP 8.0 threw an error. I need this because the property may not be set at some point, for lazy loading or state reset.
Check this example code:
<?php
declare(strict_types=1);
final class
TextContainer
{
private static string $text;
public static function has():bool
{
return isset(self::$text);
}
public static function getAfterHas():string
{
return self::$text;
}
public static function set(string $v):void
{
self::$text = $v;
}
public static function unset():void
{
unset(self::$text);
}
}
TextContainer::set('foo');
if (TextContainer::has())
{
echo TextContainer::getAfterHas();
}
TextContainer::unset();
if (TextContainer::has())
{
echo TextContainer::getAfterHas();
}
The error message it shows is: Fatal error: Uncaught Error: Attempt to unset static property TextContainer::$text.
I would prefer not using some kind of workaround like assigning null to the property, because I like the strong typing, and that would force me to type hint the property as string|null.
Any ideas? Thank you in advance.

Related

PHP Syntax Error in the Instance Declaration

i have a little syntax error which i'm not able to sort out, can anyone help ?
Syntax:
Config Class:
Error:
Do not instantiate private variables like that, you should only be using them for declaring properties and simple values.
You cannot declare a private variable (declaring them a return value from a static functions at least) like that, just do it in the constructor __construct() for the object. You will get the same error for any class you do with a private variable declaration like that and setting it as a return value for any function. Try running the below in PHPFiddle and you'll get the same error.
<?php
class A {
private $hi = B::some_function('hi');
}
class B {
public static function some_function(string) {
return $string;
}
}
?>
Instead do something like:
<?php
class A {
private $hi;
public function __construct() {
$this->hi = B::some_function('hi');
}
}
class B {
public static function some_function(string) {
return $string;
}
}
?>
Your syntax is incorrect as I've seen in that picture, simply because you didn't have a closing bracket '}' for the class User.
Just try this one.
Use semicolon for every function call as shown below,
$_table = Config::get('tables/users');
$_seassionsTable = Config::get('tables/user_sessions');
It may be fix your issue.

How do I create a PHP static class property at runtime (dynamically)?

I'd like to do something like this:
public static function createDynamic(){
$mydynamicvar = 'module';
self::$mydynamicvar = $value;
}
and be able to access the property from within the class with
$value = self::$module;
I don't know exactly why you would want to do this, but this works. You have to access the dynamic 'variables' like a function because there is no __getStatic() magic method in PHP yet.
class myclass{
static $myvariablearray = array();
public static function createDynamic($variable, $value){
self::$myvariablearray[$variable] = $value;
}
public static function __callstatic($name, $arguments){
return self::$myvariablearray[$name];
}
}
myclass::createDynamic('module', 'test');
echo myclass::module();
static variables must be part of the class definition, so you can't create them dynamically. Not even with Reflection:
chuck at manchuck dot com 2 years ago
It is important to note that calling ReflectionClass::setStaticPropertyValue will not allow you to add new static properties to a class.
But this looks very much like a XY Problem. You probably don't really want to add static properties to a PHP class at runtime; you have some use case that could be fulfilled also that way. Or that way would be the fastest way, were it available, to fulfill some use case. There well might be other ways.
Actually the use cases below are yet again possible solutions to some higher level problem. It might be worth it to reexamine the high level problem and refactor/rethink it in different terms, maybe skipping the need of meddling with static properties altogether.
I want a dictionary of properties inside my class.
trait HasDictionary {
private static $keyValueDictionary = [ ];
public static function propget($name) {
if (!array_key_exists($name, static::$keyValueDictionary) {
return null;
}
return static::$keyValueDictionary[$name];
}
public static function propset($name, $value) {
if (array_key_exists($name, static::$keyValueDictionary) {
$prev = static::$keyValueDictionary[$name];
} else {
$prev = null;
}
static::$keyValueDictionary[$name] = $value;
return $prev;
}
}
class MyClass
{
use Traits\HasDictionary;
...$a = self::propget('something');
self::propset('something', 'some value');
}
I want to associate some values to a class, or: I want a dictionary of properties inside some one else's class.
This actually happened to me and I found this question while investigating ways of doing it. I needed to see, in point B of my workflow, in which point ("A") a given class had been defined, and by what other part of code. In the end I stored that information into an array fed by my autoloader, and ended up being able to also store the debug_backtrace() at the moment of class first loading.
// Solution: store values somewhere else that you control.
class ClassPropertySingletonMap {
use Traits\HasDictionary; // same as before
public static function setClassProp($className, $prop, $value) {
return self::propset("{$className}::{$prop}", $value);
}
public static function getClassProp($className, $prop) {
return self::propget("{$className}::{$prop}");
}
}
// Instead of
// $a = SomeClass::$someName;
// SomeClass::$someName = $b;
// we'll use
// $a = ClassPropertySingletonMap::getClassProp('SomeClass','someName');
// ClassPropertySingletonMap::setClassProp('SomeClass','someName', $b);
I want to change, not create, an existing property of a class.
// Use Reflection. The property is assumed private, for were it public
// you could do it as Class::$property = $whatever;
function setPrivateStaticProperty($class, $property, $value) {
$reflector = new \ReflectionClass($class);
$reflector->getProperty($property)->setAccessible(true);
$reflector->setStaticPropertyValue($property, $value);
$reflector->getProperty($property)->setAccessible(false);
}
Static properties must be defined in the class definition. Therefore, real static properties cannot be created dynamically like regular properties.
For example, if you run this:
<?php
class MyClass
{
public static function createDynamic()
{
$mydynamicvar = 'module';
self::$mydynamicvar = $value;
}
}
MyClass::createDynamic();
var_dump(MyClass::$mydynamicvar);
var_dump(MyClass::$module);
...you'll get this error
Fatal error: Access to undeclared static property: MyClass::$mydynamicvar test.php on line 8
Notice how the error occurs on line 8 when trying to set the property instead of line 14 or 15 (as you might expect if you were simply doing it wrong and dynamically creating static properties was actually possible).
A related problem that IS possible (in PHP 5.4.0 and up) is to include various separate groups of static variable or constant declarations and group them together into one class declaration.
Here is an example:
trait Added1 // This can be located in one Include file
{
static
$x="hello"; // Can declare more variables here
}
trait Added2 // This can be located in another Include file
{
static
$y="world"; // Can declare more variables here
}
class G // Global constant and variable declarations class
{
use Added1, Added2; // Combines all variable declarations
}
echo G::$x." ".G::$y; // Shows "hello world" on the web page

How do I invoke the function named in a static property on an object?

I want to invoke a function on an object. The name of the function is stored in a static property of a class (of which the object is an instance). This invocation happens inside one of the object's methods.
None of the approaches below work (it's after the getBean()-> that I'm confused).
$this->getBean()->User::$BEANSCHEMA_FIRST_NAME;
$this->getBean()->self::$BEANSCHEMA_FIRST_NAME;
$this->getBean()->$self::$BEANSCHEMA_FIRST_NAME;
How can I accomplish this, preferrably without a weird library function like call_user_func()?
Use {}, hope this helps (Demo):
class Funcaro
{
public static $MUNKI_SELF = 'munki';
public function munki()
{
echo 'You got me :)', "\n";
}
}
class Callara extends Funcaro
{
public function get()
{
return new Funcaro();
}
public function call()
{
$this->get()->{self::$MUNKI_SELF}();
}
}
$c = new Callara();
$c->get()->munki();
$munki = 'munki';
$c->get()->$munki();
$c->get()->{Funcaro::$MUNKI_SELF}();
$c->call();
Related: PHP curly brace syntax for member variable

PHP - passing variables to classes

I trying to learn OOP and I've made this class
class boo{
function boo(&another_class, $some_normal_variable){
$some_normal_variable = $another_class->do_something();
}
function do_stuff(){
// how can I access '$another_class' and '$some_normal_variable' here?
return $another_class->get($some_normal_variable);
}
}
and I call this somewhere inside the another_class class like
$bla = new boo($bla, $foo);
echo $bla->do_stuff();
But I don't know how to access $bla, $foo inside the do_stuff function
<?php
class Boo
{
private $bar;
public function setBar( $value )
{
$this->bar = $value;
}
public function getValue()
{
return $this->bar;
}
}
$x = new Boo();
$x->setBar( 15 );
print 'Value of bar: ' . $x->getValue() . PHP_EOL;
Please don't pass by reference in PHP 5, there is no need for it and I've read it's actually slower.
I declared the variable in the class, though you don't have to do that.
Ok, first off, use the newer style constructor __construct instead of a method with the class name.
class boo{
public function __construct($another_class, $some_normal_variable){
Second, to answer your specific question, you need to use member variables/properties:
class boo {
protected $another_class = null;
protected $some_normal_variable = null;
public function __construct($another_class, $some_normal_variable){
$this->another_class = $another_class;
$this->some_normal_variable = $some_normal_variable;
}
function do_stuff(){
return $this->another_class->get($this->some_normal_variable);
}
}
Now, note that for member variables, inside of the class we reference them by prefixing them with $this->. That's because the property is bound to this instance of the class. That's what you're looking for...
In PHP, constructors and destructors are written with special names (__construct() and __destruct(), respectively). Access instance variables using $this->. Here's a rewrite of your class to use this:
class boo{
function __construct(&another_class, $some_normal_variable){
$this->another_class = $another_class;
$this->some_normal_variable = $another_class->do_something();
}
function do_stuff(){
// how can I access '$another_class' and '$some_normal_variable' here?
return $this->another_class->get($this->some_normal_variable);
}
}
You need to capture the values in the class using $this:
$this->foo = $some_normal_variable

PHP Class won't return to a String

I'm fairly new to PHP so I have a small problem as I'm learning:
I built a Class called DataStrip.php
<?php
final class DataStrip
{
public function DataStrip()
{
// constructor
}
public function stripVars($vars)
{
return $vars;
}
}
?>
and then I'm trying to pass the public function stripVars a value:
<?php
include_once ('lib/php/com/DataStrip.php');
echo($projCat);
$a = new DataStrip;
$a->stripVars($projCat);
echo($a);
?>
however, I get back this error:
( ! ) Catchable fatal error: Object of class DataStrip could not be converted to string in myfilepath
... any advice perhaps on what I could be doing wrong here? Right now this is just a test function as I'm trying to get used to OOP PHP. :)
What do you expect it to happen? You're not saving the result of what stripVars returns into a variable:
$result = $a->stripVars($projCat);
print $result;
What you are trying to do is print the object variable itself. If you want to control what happens when you try to print an object, you need to define the __toString method.
if you want to do that... you need declarate the method __toString()
<?php
final class DataStrip
{
private $vars;
public function DataStrip()
{
// constructor
}
public function stripVars($vars)
{
$this->vars = $vars;
}
public function __toString() {
return (string) $this->vars;
}
}
// then you can do
$a = new DataStrip;
$a->stripVars($projCat);
echo($a);
?>
Shouldn't you return to a variable:
$projCat = $a->stripVars($projCat);
When you echo $a you're echoing the object - not any particular function or variable inside it (since when you declare $a you're declaring it as everything in the class - variables, functions, the whole kit and kaboodle.
I also have issues with php oop, so please correct if I am wrong :)

Categories