Stacking Static Classes in PHP - php

Is there a way to make a static class where it has another static class as a member?
E.G. Parent_Class::Child_Class::Member_function();

If you mean nested classes, no. I believe they were going to be introduced at one point but ended up getting dropped.
There is namespace support, however, if that's what you're after.

No.
However, you could use one of PHP's magic methods to do what you want, perhaps:
class ParentClass {
public static function __callStatic($method,$args) {
return call_user_func_array(array('ChildClass',$method),$args);
}
}
class ChildClass {
public static function childMethod() {
...
}
}
ParentClass::childMethod($arg);

Yes, you can have nested static classes in PHP, but it's not pretty, and it takes a bit of extra work. The syntax is a little different than you have.
The trick is to statically initialize the outer class and create a static instance of the inner class.
You can then do one of two things, both are illustrated below.
refer to a static instance of the inner class (child class is actually a misnomer, because there is no inheritance relationship.)
create a static accessor method for the instance of the inner class (this is preferable because it allows for discovery.)
class InnerClass {
public static function Member_function() {
echo __METHOD__;
}
}
class OuterClass {
public static $innerClass;
public static function InnerClass() {
return self::$innerClass;
}
public static function init() {
self::$innerClass = new InnerClass();
}
}
OuterClass::init();
OuterClass::$innerClass->Member_function();
OuterClass::InnerClass()->Member_function();

No, classes are not first-class citizens in PHP so they can't be stored in variables.
You could sort of make a pass through function in your outermost class
class Parent_Class
{
public static $childClass;
public static function callChildMethod( $methodName, array $args=array() )
{
return call_user_func_array( array( self::$childClass, $methodName ), $args );
}
}
class Child_Class
{
public static function hello()
{
echo 'hello';
}
}
Parent_Class::$childClass = 'Child_Class';
Parent_Class::callChildMethod( 'hello' );

PHP does not support nested classes in any form (static or otherwise).

Related

Abstract trait't method not allowed to be static in PHP?

Here is my example:
trait FileConfig {
public static function getPathForUploads() {
$paths = static::getPaths();
//etc.
}
abstract public static function getPaths(); //doesn't work. Error: "Static function SharedDefaultConfig::getPaths() should not be abstract"
abstract public function getPaths(); //OK
public static function getPaths() {} //OK
}
Class:
class AppConfig {
use FileConfig;
public static function getPaths() {
return array(...);
}
}
Call:
AppConfig::getPathForUploads();
It's nessessary to make it static and abstract (to force classes using FileConfig to implement getPaths).
I wonder how is it possible to implement method changing it's static property? Is it a good practice or there are better solutions? Will it one day become illegal?
Thank you
This is fixed in php 7, so the following code works:
<?php
error_reporting(-1);
trait FileConfig {
public static function getPathForUploads() {
echo static::getPaths();
}
abstract static function getPaths();
}
class AppConfig {
use FileConfig;
protected static function getPaths() {
return "hello world";
}
}
AppConfig::getPathForUploads();
http://sandbox.onlinephpfunctions.com/code/610f3140b056f3c3e8defb84e6b57ae61fbafbc9
But it does not actually check if the method in AppConfig is static or not during compilation. You will only get a warning when you try to call the non-static method statically: http://sandbox.onlinephpfunctions.com/code/1252f81af34f71e901994af2531104d70024a685
You do not need to make the method static to force classes using it to implement the method. You can simply use interfaces alongside.
trait FileUploadConfig {
public static function getPathForUploads() {
$paths = static::getPaths();
//etc.
}
}
The trait was left as is. I just took away the functions for the interface.
interface PathConfiguration {
public static function getPaths();
}
The interface forces the class to implement the function. I left the static in there to correspond with the trait's specification.
class AppConfig implements PathConfiguration {
use FileUploadConfig;
public static function getPaths() {
return [];
}
}
To force classes using FileConfig to implement getPaths it's not nessessary to make abstract function static. Static means that it belongs to the class that declared it. Make it protected static, add code from trait and then you could change behaviour by inheritance from your AppConfig class.

Can I/How to... call a protected function outside of a class in PHP

I have a protected function that is defined within a certain class. I want to be able to call this protected function outside of the class within another function. Is this possible and if so how may I achieve it
class cExample{
protected function funExample(){
//functional code goes here
return $someVar
}//end of function
}//end of class
function outsideFunction(){
//Calls funExample();
}
Technically, it is possible to invoke private and protected methods using the reflection API. However, 99% of the time doing so is a really bad idea. If you can modify the class, then the correct solution is probably to just make the method public. After all, if you need to access it outside the class, that defeats the point of marking it protected.
Here's a quick reflection example, in case this is one of the very few situations where it's really necessary:
<?php
class foo {
protected function bar($param){
echo $param;
}
}
$r = new ReflectionMethod('foo', 'bar');
$r->setAccessible(true);
$r->invoke(new foo(), "Hello World");
That's the point of OOP - encapsulation:
Private
Only can be used inside the class. Not inherited by child classes.
Protected
Only can be used inside the class and child classes. Inherited by child classes.
Public
Can be used anywhere. Inherited by child classes.
If you still want to trigger that function outside, you can declare a public method that triggers your protected method:
protected function b(){
}
public function a(){
$this->b() ;
//etc
}
If the parent's method is protected, you can use an anonymous class:
class Foo {
protected function do_foo() {
return 'Foo!';
}
}
$bar = new class extends Foo {
public function do_foo() {
return parent::do_foo();
}
}
$bar->do_foo(); // "Foo!"
https://www.php.net/manual/en/language.oop5.anonymous.php
You can override this class with another where you make this public.
class cExample2 extends cExample {
public function funExample(){
return parent::funExample()
}
}
(note this won't work with private members)
But the idea of private and protected members is to NOT BE called from outside.
Another option (PHP 7.4)
<?php
class cExample {
protected function funExample(){
return 'it works!';
}
}
$example = new cExample();
$result = Closure::bind(
fn ($class) => $class->funExample(), null, get_class($example)
)($example);
echo $result; // it works!
If you want to share code between your classes you can use traits, but it depends how you want use your function/method.
Anyway
trait cTrait{
public function myFunction() {
$this->funExample();
}
}
class cExample{
use cTrait;
protected function funExample() {
//functional code goes here
return $someVar
}//end of function
}//end of class
$object = new cExample();
$object->myFunction();
This will work, but keep in mind that you don't know what your class is made of this way. If you change the trait then all of your classes which use it will be altered as well. It's also good practice to write an interface for every trait you use.
here i can give you one example like below
<?php
class dog {
public $Name;
private function getName() {
return $this->Name;
}
}
class poodle extends dog {
public function bark() {
print "'Woof', says " . $this->getName();
}
}
$poppy = new poodle;
$poppy->Name = "Poppy";
$poppy->bark();
?>
or one another way to use with latest php
In PHP you can do this using Reflections. To invoke protected or private methods use the setAccessible() method http://php.net/reflectionmethod.setaccessible (just set it to TRUE)
I am using Laravel. i was facing issue while access protected method outside of class.
$bookingPriceDetails = new class extends BookingController {
public function quotesPrice( $req , $selectedFranchise) {
return parent::quotesPrice($req , $selectedFranchise);
}
};
return $bookingPriceDetails->quotesPrice($request , selectedFranchisees());
here BookingController is Class name from which i want to get protected method. quotesPrice( $req , $selectedFranchise) is method that i want to access in different Class.

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 ?

Extending PHP static classes

I've been struggling in this area for days now, and I have reached a conclusion, but since the conclusion was not what I was looking for, before I give up, I'll try to see what other people say. Faith dies last...
Let's say we have a superclass (called "Super") and a subclass (called "Sub").
class Super {
protected static $title = 'super';
public static function get_class_name()
{
echo __CLASS__;
}
public static function get_title()
{
echo self::$title;
}
}
class Sub extends Super {
protected static $title = 'sub';
}
Now, you would probably expect since Sub extends Super, that Sub would now inherit all of Super's methods, however, it seems to only receive references to the Sub's methods.
I say this because if I call:
Sub::get_class_name();
the output is "Super", and not "Sub".
And if I call:
Sub::get_title();
again, the output is "super", and I even have the $title declared in Sub.
So this means that when I call an inherited static function, the function's scope will be the super class, not the one called upon (even if you print the backtrace, it will show that the call was made on the superclass!!!), and in order to obtain the scope as the subclass that the call is being made upon, I need to redeclare that method inside that subclass. Well this kind of defeats the purpose of extending classes, don't it?
So my question is, can I ever extend a static class, call one of the inherited methods and have the subclass's scope? or at least to be able to identify it's classname?
And if not, why would I ever want to extend static classes?
Thanks!
Again, this is not possible prior to PHP 5.3.0.
Late Static Binding was introduced in PHP 5.3.0 and allows you to do exactly what you want via the static keyword.
class Super {
protected static $title = 'super';
public static function get_class_name()
{
echo __CLASS__;
}
public static function get_title()
{
echo static::$title;
}
}
class Sub extends Super {
protected static $title = 'sub';
}
get_class_name() will still return Super though has __CLASS__ always returns the current class the method being run is declared in (kind of like __FILE__ which always returns the current file no matter if you included it or not).
For that you don't have any choice but to re-declare the function in the Sub class.
class Super {
protected static $title = 'super';
public static function get_class_name()
{
echo __CLASS__;
}
public static function get_title()
{
echo static::$title;
}
}
class Sub extends Super {
protected static $title = 'sub';
public static function get_class_name()
{
echo __CLASS__;
}
}
You can used get_called_class() to get the class name of the class you are calling, even if it is static. You don't have to declare it anywhere.
From Andrew's Example:
class Super {
public static function get_class1_name()
{
echo __CLASS__;
}
public static function get_title()
{
echo get_called_class();
}
}
class Sub extends Super {
public static function get_class2_name()
{
echo __CLASS__;
}
}
Sub::get_title(); // Echos Sub.
Sub::get_class1_Name(); // echos super
Sub::get_class2_Name(); // echos sub
Therefore you don't have to declare any variables.
Fortunately, I'm doing something for me, so I said, screw it, I'm using PHP5.3. But even so, I don't like that I have to redeclare "get _class _name" in every class, maybe I'm extending like 10 classes. So I came up with this solution:
class Super {
protected static $classname = __CLASS__;
public static function get_classname($name)
{
static::$classname = $name;
}
public static function get_classname()
{
return static::$classname;
}
}
class Sub1 extends Super { }
class Sub2 extends Super { }
class Sub3 extends Super { }
$classes = get_declared_classes();
foreach($classes as $k => $v)
{
if (is_subclass_of($v, 'Super'))
{
$v::set_classname($v);
}
}
echo Sub1::get_classname(); // Sub1
echo Sub2::get_classname(); // Sub2
echo Sub3::get_classname(); // Sub3
It might seem a little dirty, but I don't think it's that bad. With this done, you can finally extend static methods without having to re-declare methods.

What exactly are late static bindings in PHP?

What exactly are late static bindings in PHP?
You definitely need to read Late Static Bindings in the PHP manual. However, I'll try to give you a quick summary.
Basically, it boils down to the fact that the self keyword does not follow the same rules of inheritance. self always resolves to the class in which it is used. This means that if you make a method in a parent class and call it from a child class, self will not reference the child as you might expect.
Late static binding introduces a new use for the static keyword, which addresses this particular shortcoming. When you use static, it represents the class where you first use it, ie. it 'binds' to the runtime class.
Those are the two basic concepts behind it. The way self, parent and static operate when static is in play can be subtle, so rather than go in to more detail, I'd strongly recommend that you study the manual page examples. Once you understand the basics of each keyword, the examples are quite necessary to see what kind of results you're going to get.
From PHP: Late Static Bindings - Manual:
As of PHP 5.3.0, PHP implements a feature called late static binding which can be used to reference the called class in the context of static inheritance.
Late static binding tries to solve that limitation by introducing a keyword that references the class that was initially called at runtime. ... It was decided not to introduce a new keyword, but rather use static that was already reserved.
Let's see an example:
<?php
class Car
{
public static function run()
{
return static::getName();
}
private static function getName()
{
return 'Car';
}
}
class Toyota extends Car
{
public static function getName()
{
return 'Toyota';
}
}
echo Car::run(); // Output: Car
echo Toyota::run(); // Output: Toyota
?>
Late static bindings work by storing the class named in the last "non-forwarding call". In case of static method calls, this is the class explicitly named (usually the one on the left of the :: operator); in case of non-static method calls, it is the class of the object. A "forwarding call" is a static one that is introduced by self::, parent::, static::, or, if going up in the class hierarchy, forward_static_call(). The function get_called_class() can be used to retrieve a string with the name of the called class and static:: introduces its scope.
There is not very obvious behavior:
The following code produces 'alphabeta'.
class alpha {
function classname(){
return __CLASS__;
}
function selfname(){
return self::classname();
}
function staticname(){
return static::classname();
}
}
class beta extends alpha {
function classname(){
return __CLASS__;
}
}
$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta
However, if we remove the declaration of the classname function from the beta class, we get 'alphaalpha' as the result.
I'm quoting from the book: "PHP Master write cutting-edge code".
Late static binding was a feature introduced with php 5.3. It allows
us to inherit static methods from a parent class, and to reference
the child class being called.
This means you can have an abstract class with static methods, and
reference the child class's concrete implementations by using the
static::method() notation instead of the self::method().
Feel free to take a look at the official php documentation as well:
http://php.net/manual/en/language.oop5.late-static-bindings.php
The clearest way to explain Late Static Binding is with a practicle example. I'm using it in a Template method pattern. See below.
abstract class AbstractTemplate {
public const AWESOME_LIST = [''];
public function someFunction(): void {
$awesomeList = $this->getAwesomeList();
// OUTPUT: ['harry','henk','john'];
var_dump($awesomeList);
}
/**
* This function gets static constants from CHILD classes
*/
public function getAwesomeList(): array
{
return static::AWESOME_LIST;
}
}
class ConcreteTemplate extends AbstractTemplate {
public const AWESOME_LIST = ['harry','henk','john'];
public function someFunction(): void {
parent::someFunction();
}
}
$concreteTemplate = new ConcreteTemplate();
$concreteTemplate->someFunction();
Notice the static keyword in method getAwesomeList.
Let's change a bit now:
public function getAwesomeList(): array
{
return self::AWESOME_LIST;
}
The output of the var_dump at someFunction would be:
array (size=1)
0 => string '' (length=0)
The static keyword is used in a Singleton design pattern.
See link: https://refactoring.guru/design-patterns/singleton/php/example
The simplest example to show the difference.
Note, self::$c
class A
{
static $c = 7;
public static function getVal()
{
return self::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 7
Late static binding, note static::$c
class A
{
static $c = 7;
public static function getVal()
{
return static::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 8
Looking at it from a "why would I use this?" perspective, it's basically a way to change the context from which the static method is being interpreted/run.
With self, the context is the one where you defined the method originally. With static, it's the one you're calling it from.
For example:
abstract class Builder {
public static function build() {
return new static;
}
}
class Member extends Builder {
public function who_am_i() {
echo 'Member';
}
}
Member::build()->who_am_i();
Also, watch if you update static variables in child classes. I found this (somewhat) unexpected result where child B updates child C:
class A{
protected static $things;
}
class B extends A {
public static function things(){
static::$things[1] = 'Thing B';
return static::$things;
}
}
class C extends A{
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}
print_r(C::things());
// Array (
// [2] => Thing C
// )
B::things();
print_r(C::things());
// Array (
// [2] => Thing C
// [1] => Thing B
// )
You can fix it by declaring the same variable in each child class, for example:
class C extends A{
protected static $things; // add this and B will not interfere!
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}

Categories