How to get the name of the calling class (in PHP) - php

define('anActionType', 1);
$actionTypes = array(anActionType => 'anActionType');
class core {
public $callbacks = array();
public $plugins = array();
public function __construct() {
$this->plugins[] = new admin();
$this->plugins[] = new client();
}
}
abstract class plugin {
public function registerCallback($callbackMethod, $onAction) {
if (!isset($this->callbacks[$onAction]))
$this->callbacks[$onAction] = array();
global $actionTypes;
echo "Calling $callbackMethod in $callbacksClass because we got {$actionTypes[$onAction]}" . PHP_EOL;
// How do I get $callbacksClass?
$this->callbacks[$onAction][] = $callbackMethod;
}
}
class admin extends plugin {
public function __construct() {
$this->registerCallback('onTiny', anActionType);
}
public function onTiny() { echo 'tinyAdmin'; }
}
class client extends plugin {
public function __construct() {
$this->registerCallback('onTiny', anActionType);
}
public function onTiny() { echo 'tinyClient'; }
}
$o = new core();
$callbacksClass should be admin or client. Or am I missing the point here completely and should go about this another way? It should be noted that I will only accept an answer that does not require me to send the classname as an argument to the registerCallback method.

If anyone came here looking for how to get the name of a calling class from another class like I did, check this out https://gist.github.com/1122679
EDIT: pasted code
function get_calling_class() {
//get the trace
$trace = debug_backtrace();
// Get the class that is asking for who awoke it
$class = $trace[1]['class'];
// +1 to i cos we have to account for calling this function
for ( $i=1; $i<count( $trace ); $i++ ) {
if ( isset( $trace[$i] ) ) // is it set?
if ( $class != $trace[$i]['class'] ) // is it a different class
return $trace[$i]['class'];
}
}
EG
class A {
function t() {
echo get_calling_class();
}
}
class B {
function x() {
$a = new A;
$a->t();
}
}
$b = new B;
$b->x(); // prints B

Use get_class():
$this->callbacks[$onAction][] = $callbackMethod;
$className = get_class($this);
// Call callback method
$className->$callbackMethod();

You should really do something like:
$this->registerCallback(array($this, 'onTiny'), anActionType);
That is how PHP works with handles to object methods.

From PHP 8+ you can use static::class rather than get_class($this).
This one is also auto-fixed with PHP Code Sniffer and rule SlevomatCodingStandard.Classes.ModernClassNameReference

Related

PHP OOP declaring a variable to an upper class

First of all, I want to write two class.
<?php
class A
{
function load($v)
{
$this->$v = "stack";
}
}
class Base
{
var $lib = null;
function __construct()
{
$this->lib = new A();
}
}
$bs = new Base();
$bs->lib->load("libx");
// Current calling method
$bs->lib->libx;
// But I want this
$bs->libx;
?>
I write a MVC fremawork.
CodeIgniter can do this but I could not.
My english is poor. Because of this, don't talk me complicated please.
You can add a magic __get method to Base to look for the property in lib, and return it if it exists:
class A
{
function load($v)
{
$this->$v = "stack";
}
}
class Base
{
var $lib = null;
function __construct()
{
$this->lib = new A();
}
public function __get($v)
{
if (property_exists($this->lib, $v)) {
return $this->lib->$v;
}
}
}
Usage:
$bs = new Base();
$bs->lib->load("libx");
echo $bs->lib->libx, PHP_EOL;
echo $bs->libx, PHP_EOL;
Output:
stack
stack

PHP mandatory function call

I understand that one can use interfaces to mandate the definition of a function, but I cannot find something that enables one to mandate function calls, such that e.g. if I create a class being a member of another class (via extends, etc), with a function, for that class to automatically ensure that mandatory functions are called in part with that function.
I mean, to clarify further:
class domain {
function isEmpty($input) {
//apply conditional logic and results
}
}
class test extends domain {
function addTestToDBTable($test) {
/**
* try to add but this class automatically makes it so that all rules of
* class domain must be passed before it can run
* - so essentially, I am no longer required to call those tests for each and
* every method
**/
}
}
Apologies if this appears incoherent by any means. Sure, it seems lazy but I want to be able to force context without having to concern abou
Update:
Okay, to clarify further: in PHP, if I extend and declare a __construct() for a child class, that child class will override the parent __construct(). I do not want this, I want the parent construct to remain and mandate whatever as it pleases just as the child class may do so also.
I guess it can be done in two different ways.
Aspect Oriented Programming
Have a look here https://github.com/AOP-PHP/AOP
Generate or write Proxy classes
A really simple example could be:
<?php
class A {
public function callMe() {
echo __METHOD__ . "\n";
}
}
class B extends A {
// prevents instantiation
public function __construct() {
}
public function shouldCallMe() {
echo __METHOD__ . "\n";
}
public static function newInstance() {
return new ABProxy();
}
}
class ABProxy {
private $b;
public function __construct() {
$this->b = new B();
}
public function __call($method, $args) {
$this->b->callMe();
return call_user_func_array(array($this->b, $method), $args);
}
}
// make the call
$b = B::newInstance();
$b->shouldCallMe();
// Outputs
// ------------------
// A::callMe
// B::shouldCallMe
Hopes this helps a bit.
Sounds like you want a Decorator.
See This answer for a detailed explanation on how to do it. Note that it does not require a class extension.
I would use a domain-validating decorator with some doc-block metaprogramming magic. But this is really a job for an entire library, which no doubt exists.
fiddle
<?php
class FooDomain {
public static function is_not_empty($input) {
return !empty($input);
}
}
class Foo {
/**
* #domain FooDomain::is_not_empty my_string
*/
public function print_string($my_string) {
echo $my_string . PHP_EOL;
}
}
$foo = new DomainValidator(new Foo());
$foo->print_string('Hello, world!');
try {
$foo->print_string(''); // throws a DomainException
} catch (\DomainException $e) {
echo 'Could not print an empty string...' . PHP_EOL;
}
// ---
class DomainValidator {
const DOMAIN_TAG = '#domain';
private $object;
public function __construct($object) {
$this->object = $object;
}
public function __call($function, $arguments) {
if (!$this->verify_domain($function, $arguments)) {
throw new \DomainException('Bad domain!');
}
return call_user_func_array(
array($this->object, $function),
$arguments
);
}
public function __get($name) {
return $this->object->name;
}
public function __set($name, $value) {
$this->object->name = $value;
}
private function verify_domain($function, $arguments) {
// Get reference to method
$method = new \ReflectionMethod($this->object, $function);
$domains = $this->get_domains($method->getDocComment());
$arguments = $this->parse_arguments(
$method->getParameters(),
$arguments
);
foreach ($domains as $domain) {
if (!call_user_func(
$domain['name'],
$arguments[$domain['parameter']]
)) {
return false;
}
}
return true;
}
private function get_domains($doc_block) {
$lines = explode("\n", $doc_block);
$domains = array();
$domain_tag = DomainValidator::DOMAIN_TAG . ' ';
foreach ($lines as $line) {
$has_domain = stristr($line, $domain_tag) !== false;
if ($has_domain) {
$domain_info = explode($domain_tag, $line);
$domain_info = explode(' ', $domain_info[1]);
$domains[] = array(
'name' => $domain_info[0],
'parameter' => $domain_info[1],
);
}
}
return $domains;
}
private function parse_arguments($parameters, $values) {
$ret = array();
for ($i = 0, $size = sizeof($values); $i < $size; $i++) {
$ret[$parameters[$i]->name] = $values[$i];
}
return $ret;
}
}
Output:
Hello, world!
Could not print an empty string...

Is it possible to pass the current class into another one as reference in php ? If yes, how

Here's what I did:
Let's suppose two classes one event and the other one GoogleCalendar.
class Event {
private $googleCalendar;
public function __construct() {
$this->googleCalendar = new GoogleCalendar();
$this->googleCalendar->set_event($this);
}
}
class GoogleCalendar {
private $event;
public function set_event(&$event) {
$this->event = $event;
}
}
So, when I access the event element of the GoogleCalendar class, it says the object do not exist. Where is the problem ?
Thanks in advance and let me know if anything is not clear !
Etienne NOEL
Object is automatically passed by reference, you don't need the &$event as an argument.
Here's an example:
<?php
error_reporting(E_ALL);
class a
{
public $prop = 'test';
function __construct()
{
$b = new b();
$b->preform_action($this);
}
}
class b
{
public function preform_action($object)
{
if (is_object($object)) {
var_dump($object);
}
}
}
$a = new a();
?>

is there a way puting variables in controller from an extended framework class?

hello im still on learning mvc by makeing one, and today i realize that i have a miss on how things work.
class Framework
{
function __construct()
{
require 'libraries/language/l.php';
/*
$l['hello'] = 'hello';
$l['helloworld'] = 'helloworld';
etc
*/
}
}
class Controller extends Framework
{
function index()
{
#missing ?
echo $l;
}
}
ok the first question is how can i echo $l from my controller files ? is there a way to do that ?
edit* same for this.
function library( $lib ){
if (file_exists('libraries/lib.'. $lib .'.php')) {
require 'libraries/lib.'. $lib .'.php';
if (class_exists($lib)) {
$class = ucfirst($lib);
$$lib = new $class;
return TRUE;
}
if (!class_exists($lib)) {
return FALSE;
}
}
}
thanks for looking in.
Adam ramadhan
Pass the data through object protected properties:
class Framework
{
protected $l = array();
function __construct()
{
require 'libraries/language/l.php';
$this->l['hello'] = 'hello';
$this->l['helloworld'] = 'helloworld';
}
}
class Controller extends Framework
{
function index()
{
echo $this->l['hello'];
}
}
Well, that means for each Controller instance, you are going to keep a big array inside it.
Actually, you can make a singleton class that provides translation for text:
class Language
{
private static $instance;
public $l = array();
private function __construct() {
require 'libraries/language/l.php';
$this->l = $l;
}
public static function getInstance() {
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
}
And you can have a shorthand function for it:
function l($text) {
return Language::getInstance()->l[$text];
}
And then use it:
echo l('hello') . "\n";

How can I get a list of methods that are originally *defined* in a class in php?

I'm trying to get a list of methods that were actually defined in a definition for a given class (not just inherited from another class). For example:
class A
{ function bob()
{
}
}
class B extends A
{ function rainbrew()
{
}
}
class C extends B
{ function bob()
{
}
}
echo print_r(get_defined_class_methods("A"), true)."<br>\n";
echo print_r(get_defined_class_methods("B"), true)."<br>\n";
echo print_r(get_defined_class_methods("C"), true)."<br>\n";
I'd like the result to be:
array([0]=>bob)
array([0]=>rainbrew)
array([0]=>bob)
Is this possible?
You can use Reflection for this:
$reflectA = new ReflectionClass('A');
print_r($reflectA->getMethods());
This will actually give you an array of ReflectionMethod objects, but you can easily extrapolate what you need from there. ReflectionMethods provide a getDeclaringClass() function for this, so you can find which functions were declared in which class:
$reflectC = new ReflectionClass('C');
$methods = $reflectC->getMethods();
$classOnlyMethods = array();
foreach($methods as $m) {
if ($m->getDeclaringClass()->name == 'C') {
$classOnlyMethods[] = $m->name;
}
}
print_r($classOnlyMethods);
This will give:
Array ( [0] => bob )
So, as a final solution, try this:
function get_defined_class_methods($className)
{
$reflect = new ReflectionClass($className);
$methods = $reflect->getMethods();
$classOnlyMethods = array();
foreach($methods as $m) {
if ($m->getDeclaringClass()->name == $className) {
$classOnlyMethods[] = $m->name;
}
}
return $classOnlyMethods;
}
I haven't tried it, but it looks like you want to use get_class_methods
<?php
class myclass {
// constructor
function myclass()
{
return(true);
}
// method 1
function myfunc1()
{
return(true);
}
// method 2
function myfunc2()
{
return(true);
}
}
$class_methods = get_class_methods('myclass');
// or
$class_methods = get_class_methods(new myclass());
foreach ($class_methods as $method_name) {
echo "$method_name\n";
}
?>
The above example will output:
myclass myfunc1 myfunc2

Categories