For testing my stuff i would like to automaticaly instantiate one instance each per child of a parent class i name, without calling the class name manually (its too many).
For example:
Class Animal {
public weight;
}
Class Dog extends Animal {
public weight = 20;
}
Class SmallDog extends Dog {
public weight = 18;
}
Class Cat extends Animal {
public weight = 10;
}
function xy(){
$classes = array();
foreach parent->child as child(){
$classes[] = new child()
}
//$classes = [Dog, SmallDog, Cat]
}
Is something like (tm) doable and if so, how ?
As further information, i have an autoload_register that holds each class, but it also holds various classes i dont want to instantiate.
Also, relative to the above example, i have Animal, Dog and Cat all assembled in a single file, lets call it animal.php.
In the code above, i would except to get an instance of anything below Animal, including SmallDog. If its not possible that way, i would be okay with getting Dog and Cat and calling the function with parent being Dog (to get SmallDog instantiated).
thanks for your advice,
This is not really useful in real case scenarios but using #axiac comment you can implement ChildrenResolver class:
class ChildrenResolver
{
protected $defaultClasses = [
0 => 'stdClass',
1 => 'Exception',
2 => 'ErrorException',
// ...
];
protected $declaredClasses;
public function __construct(array $declaredClasses = null)
{
if (is_null($declaredClasses)) {
$declaredClasses = array_diff(
get_declared_classes(),
$this->defaultClasses
);
}
$this->declaredClasses = $declaredClasses;
}
public function getChildClasses($class)
{
return array_filter(
$this->declaredClasses,
function ($declaredClassName) use ($class) {
$declaredClass = new ReflectionClass($declaredClassName);
while(($parent = $declaredClass->getParentClass())) {
if ($parent->name === $class) {
return true;
}
$declaredClass = $parent;
}
return false;
}
);
}
public function getDirectChildClasses($class)
{
return array_filter(
$this->declaredClasses,
function ($declaredClassName) use ($class) {
$declaredClass = new ReflectionClass($declaredClassName);
$parent = $declaredClass->getParentClass();
return $parent ? $parent->name === $class : false;
}
);
}
}
The idea is pretty simple. We loop over declared classes (obtained via get_declared_classes), reflect every class using ReflectionClass and compare parent, which we get from ReflectionClass::getParentClass, with given parent. For the sake of convinience I used array_filter function.
Having this class you can resolve children like this:
$childrenResolver = new ChildrenResolver;
var_dump($childrenResolver->getChildClasses('Animal'));
var_dump($childrenResolver->getDirectChildClasses('Animal'));
var_dump($childrenResolver->getChildClasses('Dog'));
Here is working demo.
Related
I have a model defined as follows:
class User extends ActiveRecord\Model {
function get_name() {
return $this->first_name . " " . $this->surname;
}
}
however when I show $item->attributes(); then name doesn't appear. Am I being an idiot here? If so, how do I get my custom attributes into the model?
Thanks,
Gareth
Here's my simple solution. I've overriding the attributes method and adding any methods that start with "get_attribute_" so I can use them during serialization:
class BaseModel extends ActiveRecord\Model
{
public function attributes()
{
$attrs = parent::attributes();
$modelReflector = new ReflectionClass(get_class($this));
$methods = $modelReflector->getMethods(~ReflectionMethod::IS_STATIC & ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method)
{
if (preg_match("/^get_attribute_/", $method->getName()))
{
$attrs[str_replace('get_attribute_', '', $method->getName())] = $method->invoke($this);
}
}
return $attrs;
}
}
The resulting models that use this would look like this:
class User extends BaseModel
{
public $loginSessionId;
function get_attribute_loginSessionId(){
return $this->loginSessionId;
}
}
This way I can manually tack on the loginSessionId (or whatever else I want) and have it show up in the serialized values.
The attributes() method will indeed return only the values for your model's table columns (not aliased).
But $item->name should give you the expected result. You can also add the setter.
To get an array of all the attributes, you can add this method to your model:
public function all_attributes() {
$custom_attr = [];
foreach (static::$getters as $getter) {
$key = substr($getter, 4);
$custom_attr[$key] = $this->$key;
}
return $custom_attr + $this->attributes();
}
(don't forget to add your getters to the $getters array, the ActiveRecord model will use it)
You have to check what the attributes function does.
You might need to override it to take into account your custom attributes, or you might have to add your custom attributes to some _properties property in the ancestor
Can you show us how you created $item? PHPActiveRecord needs you to set the attributes in the constructor call (new User($attributes)) or directly on the properties ($user->first_name = 'Gareth').
EDIT
I'm not sure the attributes() method would pick up the custom getter. It seems that it just returns the attributes property of the model.
https://github.com/kla/php-activerecord/blob/master/lib/Model.php#L566
I solved this as follows:
Create a class that derives from ActiveRecord\Model and include this function:
public function properties()
{
$attrs = $this->attributes();
$modelReflector = new ReflectionClass(get_class($this));
$methods = $modelReflector->getMethods(~ReflectionMethod::IS_STATIC & ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method)
{
if (preg_match("/^get_/", $method->getName()))
{
$attrs[str_replace('get_', '', $method->getName())] = $method->invoke($this);
}
}
return $attrs;
}
This returns all of the attributes, custom or otherwise, as long as I derive my models from the right class (not ActiveRecord\Model).
Actually, it is easily implemented like this # add this to https://github.com/kla/php-activerecord/blob/master/lib/Model.php#L520:
// check for attribute as getter
if ( method_exists( $this, "get_{$name}" ) ){
$method = "get_{$name}";
$var = $this->$method();
return $var;
}
But I prefer to do it like this (cleaner/optimized code) :
SomeModel.php:
/**
* gets templatefile of outputplugin, wrapper function for template comfortability
*
* NOTE 2: never implement functions in model, try redirecting
* to manager class (=lowmemory footprint, imagine xxxxx models with xxxx similar functions)
*
* #param string $varname variable description
* #return string
*/
public function get( $varname )
{
switch( $varname ){
case "foo" : return SomeModel::getManager()->getFoo(); break;
default: return "";
}
}
add this to https://github.com/kla/php-activerecord/blob/master/lib/Model.php#L520:
// check for attribute as getter
if ( method_exists( $this, "get" ) && $this->get( $name ) ){
$var = $this->get( $name );
return $var;
}
I have the following:
class A
{
public function getDependencies()
{
//returns A.default.css, A.default.js, A.tablet.css, A.tablet.js, etc,
//depending on what files exist and what the user's device is.
}
}
In class B, which extends A, if I call getDependencies I will get things like: B.default.css, B.default.js and so on.
What I want to do now is include the results of A as well, without having to override getDependencies() in B. In fact, I'm not even sure if overriding would work, at all. Is this possible?
This is for dynamic CSS/JS loading for templates, and eventually compilation for production as well.
EDIT= I should point out that what getDependencies returns is dynamically generated, and not a set of stored values.
EDIT2= The idea I have is that just inheriting from A will provide the behavior. I probably need some kind of recursion that goes through the hierarchy tree, starting from B, to B's parent, and all the way up to A, without any method overriding happening along the way.
Use parent::getDependencies(), e.g.:
class B
{
public function getDependencies()
{
$deps = array('B.style.js' 'B.default.js', 'B.tables.js' /*, ... */);
// merge the dependencies of A and B
return array_merge($deps, parent::getDependencies());
}
}
You can also try this code which uses ReflectionClass in order to iterate over all parents:
<?php
class A
{
protected static $deps = array('A.default.js', 'A.tablet.js');
public function getDependencies($class)
{
$deps = array();
$parent = new ReflectionClass($this);
do
{
// ReflectionClass::getStaticPropertyValue() always throws ReflectionException with
// message "Class [class] does not have a property named deps"
// So I'm using ReflectionClass::getStaticProperties()
$staticProps = $parent->getStaticProperties();
$deps = array_merge($deps, $staticProps['deps']);
}
while ($parent=$parent->getParentClass());
return $deps;
}
}
class B extends A
{
protected static $deps = array('B.default.js');
}
class C extends B
{
protected static $deps = array('C.default.js');
}
$obj = new C();
var_dump( $obj->getDependencies($obj) );
On Ideone.com
It's pretty easy using the reflection API.
I can simply iterate through the parent classes:
$class = new \ReflectionClass(get_class($this));
while ($parent = $class->getParentClass())
{
$parent_name = $parent->getName();
// add dependencies using parent name.
$class = $parent;
}
Credits to ComFreek who pointed me to the right place.
You can use self keyword - this will returns A class values and then you can use $this to get the B class values.
I am trying to inherit a set of different parent class and even not inherit any class but as per some condition.
For example, Here is what I would like to do
$choice = 2;
switch($choice) {
case 1:
class child extends parent1
break;
case 2:
class child extends parent2
break;
default:
class child
//extend nothing
break;
}
I think you can figure out what I am trying achieve here.
parent classes
class car { }
Child classes
class ferari extends car { }
class ford extends car { }
grandchild classes
class automaticcar { }
class manualcar { }
Now this grandclasses need to interit a parent as per the value sent from the form using post. Something like this
$brand = $_POST['brand'];
if(isset($brand) && !empty($brand)) {
class automaticcar extends $brand
}
else {
class automaticcar extends car //or even nothing
}
//And then I wish to write the remaining portion of the class
The kind of inheritance you are trying to obtain is not attainable using a language which inheritance is based on classes.
The closer solution you can obtain is using a sort of decorator pattern with a bit of magic methods. something like this:
$choice = 2;
switch($choice) {
case 1:
$obj = new child(new parent1());
break;
case 2:
$obj = new child(new parent2());
break;
default:
//extend nothing
$obj = new child();
break;
}
with child being similar to this:
class child {
function __construct($composeObj) {
$this->core = $composeObj;
// wathever you need to iniyialize
}
function __call($name, $params) {
return call_user_func(array($sthis->core, $name), $parameters);
}
// other functions
} // eo child
This solution have some caveats but if you can cope with them (the object does not belongs to the family of the composited object, call_user_func does not pass the parameters by reference) this is a suitable solution.
A better solution is the factory approach suggested by sandeepan but you already refused it.
A Ferrari is not different to a Ford in the properties or methods it supplies. They are both still cars. They just have different values for their attributes. Creating a spezialized subclass shouldn't be necessary for that. Instead try this route:
class Car
{
protected $_manufacturer;
protected $_engine;
protected $_gear;
protected $_price;
protected $_color;
public function __construct($manufacturer, $engine, $gear, $price, $color)
{
// setting properties
}
}
class CarFactory
{
public static function createFerrari()
{
$engine = new Engine(500); // PS
$gear = new Gear(6, 'manual');
return new Car('Ferrari', $engine, $gear, '250000', 'red');
}
public static function createFord()
{
$engine = new Engine(90); // PS
$gear = new Gear(5, 'automatic');
return new Car('Ford', $engine, $gear, '50000', 'black');
}
// other car creation methods ...
}
If you extend a class, you are creating an is-a relationship. The subclass is a specialized parent class. Gear and Engine is nothing a Car is, but something a car has. Whenever you can describe a class to have something, it's a candidate for it's own class or for just being an attribute. Whether it should be it's own class depends on whether the thing encapsulated own unique state and responsibiliy.
First off, I really don't think you understand object oriented principles well enough to ask for this functionality. It's not really needed with the style of OOP that PHP implements.
You are requesting something like conditional mix-ins. It's possible to implement it, but it is a huge kludge and should be avoided. Here's something I put together a while ago when I was just testing some concepts:
<?php
class Mixin
{
private $objects = array();
private $funcs = array();
public function addMixin(Mixable $object)
{
$exported_vars = $object->exportVars();
foreach ($exported_vars as $key => &$ref)
$this->$key = &$ref;
$vars = array();
foreach (array_keys(get_object_vars($this)) as $key)
$vars[$key] = &$this->$key;
$object->importVars($vars);
$this->objects[] = $object;
}
public function __call($method, $args)
{
if (!isset($this->funcs[$method]))
{
$found = false;
foreach ($this->objects as $obj)
{
if (method_exists($obj, $method))
{
$found = true;
$this->funcs[$method] = array($obj, $method);
break;
}
}
if (!$found)
throw new Exception("method doesn't exist");
}
return call_user_func_array($this->funcs[$method], $args);
}
}
class Mixable
{
public function exportVars()
{
$vars = array();
foreach (array_keys(get_object_vars($this)) as $key)
{
$vars[$key] = &$this->$key;
}
return $vars;
}
public function importVars($vars)
{
foreach ($vars as $key => &$ref)
{
$this->$key = &$ref;
}
}
}
?>
You would use it like:
<?php
class Parent1 extends Mixable
{
protected $name = 'Parent 1';
public function p1()
{
print "P1\n";
}
}
class Parent2 extends Mixable
{
protected $name = 'Parent 2';
public function p2()
{
print "P2\n";
}
}
class Child1 extends Mixin
{
public function whoAmI()
{
print $this->name."\n";
}
}
$foo = new Child1();
if (mt_rand(1, 2) == 1)
{
$foo->addMixin(new Parent1());
$foo->p1();
}
else
{
$foo->addMixin(new Parent2());
$foo->p2();
}
$foo->whoAmI();
?>
Please do not try to use the code! Even if it were production ready, it's a terrible concept. I put it here to show you how it would work.
I think what you really should be doing is something more like a Factory pattern: build a CarFactory class that returns a properly subclassed Car. (Or you could create a factory method within a Car class.)
It could be something like Car::get($_POST['brand']).
Is your question "Condition based inheritance good?" Then yes it looks necessary in many cases. But I think it would be better to initiate objects conditionally instead of defining extended classes inside condition.
Updates
As far as I understand you want to have different attributes/functions of the child class depending on condition. I faced a similar need/problem in my project. There it was relating to view logic. You may check How is my approach to reuse view logic in my project?
If I understand your problem correctly, then you should have the child classes ready beforehand like this in separate php files:-
child1 class
class1 child extends parent1
child2 class
class2 child extends parent2
And in the condition part do something like:-
$choice = 2;
switch($choice) {
case 1:
include /path/to/child1;
$obj = new child1();
break;
case 2:
include /path/to/child2;
$obj = new child2();
break;
default:
include /path/to/child;
$obj = new child();
//extend nothing
break;
}
I know I'm almost SIX years late. But just in case someone lands here again, I decided to put it here.
Please note that I do not assume the implicit understanding that the class names Car, Ferrari, Ford etc are vehicles. So as to be able to apply this pattern in a generic fashion.
I'll use either of the following approaches in the decreasing order of preference:
Class alias PHP Manual (PHP 5 >= 5.3.0, PHP 7)
// Assuming $my_brand is the required brand
if (!class_exists($my_brand))
{
// Raise suitable warning here and exit
exit('Brand ' . $my_brand . 'not found.');
}
class_alias($my_brand, 'MyBrand');
class AutomaticCar extends MyBrand
{
}
Conditional stacking of inheritance (Too much work, but useful in a larger size project)
// File: lib/MyBrand/Ferrari.php
class MyBrand extends Ferrari
{
}
// File: lib/MyBrand/Ford.php
class MyBrand extends Ford
{
}
// Then in your main code, assuming $my_brand is the required brand
if (!file_exists('lib/MyBrand/' . $my_brand . '.php'))
{
// Raise suitable warning here and exit
exit('Brand ' . $my_brand . 'not found.');
}
class AutomaticCar extends MyBrand
{
}
Other patterns that I can right now (such as Factory Design and Decorator Pattern) think of would take different routes which doesn't comply with the exact topic. So thats all for now.
First thing i want to say that it's not an easy question to explain, so please be patient if it seems confusing.
I have a set of classes like this
class Product {
public static $static_type = 'product';
public static $static_table = 'product_table';
public function __construct($params) { //do some }
}
and then there are the classes News, Events etc
From another class i need to access to those static variables inside these classes in an iterative way. Something like:
//...
if (Product::$static_type) { //do some }
else if (News::$static_type) { //do other }
//...
I want to trasform it in a cycle, like foreach in a way like this (it's not correct but makes sense to my question)
foreach ($classes as $class) {
echo $class::$static_type; //brrrr, just to render the idea :)
}
So i think about a singleton/static class that has a static method returning an array of my classes (not instantiated). Like this:
class Conf {
public function __construct() {
//nothing
}
public static function get_class_array () {
//how to do this???
}
}
and then
foreach (Conf::get_class_array() as $class) {
echo $class::$static_type; //brrrr, just to render the idea :)
}
How i can reach this? I don't want to instantiate Product, News or others in this case.
Edit: eval is evil, i don't want to use it. No tricks with get_declared_class, if there's no way to solve I will use reflection, that i think it's the more elegant way among the mentioned :(.
Edit: in the meantime i'll do the Conf::get_class_array() in this way
public static function get_class_array () {
return array(new ReflectionClass('Prodotto'), new ReflectionClass('News'));
}
and then call it here:
foreach (Conf::get_class_array() as $class) {
echo $class->getStaticPropertyValue('static_type');
}
I don't think you can do this. You could however do one of these:
$properties = get_class_vars('Product');
echo $properties['static_type'];
or
$class = new ReflectionClass('product');
echo $class->getStaticPropertyValue('static_type');
Note that in PHP 5.3 echo $class::$static_type; will work (http://php.net/manual/en/language.oop5.static.php)
Until 5.3.0, you can try this method. Create a container class as you suggested (we'll call it Conf to stick with what you had), and provide two methods for setting and getting applicable classes that you want to iterate over:
<?php
class Conf {
private static $instance;
private $classes = array();
public static function getInstance() {
if ( is_null(self::$instance) ) {
self::$instance = new self();
}
return self::$instance;
}
public function registerClass($className) {
// Use associative index to maintain uniqueness
$this->classes[$className] = $className;
}
public function getRegisteredClasses() {
return $this->classes;
}
}
Some example classes and how to register them:
class X {
public static $a = "catus";
public static $b = "pants";
}
class Y {
public static $a = "apples";
public static $b = "bananers";
}
$conf = Conf::getInstance();
$conf->registerClass("X");
$conf->registerClass("Y");
Now, to access and/or alter the static members, you can do something like the following (using RefelectionClass as tom Haigh pointed out):
$conf = Conf::getInstance();
echo "<pre>";
foreach ( $conf->getRegisteredClasses() as $class ) {
$reflection = new ReflectionClass($class);
echo "<hr/>Class: $class\n";
// Access example
print_r( $reflection->getStaticProperties() );
// Alter example
$reflection->setStaticPropertyValue("a",
$reflection->getStaticPropertyValue("a") . "-modified"
);
print_r( $reflection->getStaticProperties() );
}
If you have a class naming convention like Com_Example_Static_X and Com_Example_Static_Y, you can simplify Conf->getRegisteredClasses() (and even make it a static method if you so desire) by doing as n3rd suggested:
class Conf {
// ....
static public function getMatchingClasses($pattern="/^Com_Example_Static_.+$/") {
$response = array();
foreach ( get_declared_classes() as $className ) {
if ( preg_match($pattern, $className, $m) ) {
$response[] = $className;
}
}
return $response;
}
}
And, of course, update your foreach to:
foreach ( Conf::getMatchingClasses() as $class ) {
// ...
}
Hope that was helpful.
You can use get_declared_classes() to get a list of classes. This will be all class though, not just the ones you've declared.
You should make all your classes inherit from a base class:
class Product extends MyBase {}
Then you can list the classes like this
function get_class_array()
{
$myClasses = array();
foreach (get_declared_classes as $class)
{
if (is_subclass_of($class, 'MyBase'))
$myClasses[] = $class;
}
return $myClasses;
}
Then you can get the data like this:
foreach (get_class_array() as $class)
echo eval("return $class::\$foo;"); // Yes yes, eval is evil, we know...
To get a list of classes, you can use get_declared_classes. Then you'll have to determine which of those classes you want to process.
You could do this by looking for a common base class with is_subclass_of, or using ReflectionClass to see if it has the static member variables you are interested in.
I don't think there's an easy way to do this. Here are a few ideas off the top of my head how you could go about doing this:
Use get_declared_classes() to retrieve a list of all defined classes and check them against your naming scheme (e.g. MyNamespace_*) or whether they implement an interface (e.g. MyStaticEnumerable).
Kinda like the above, but a little more sophisticated: write your on class loader and have it check whether a loaded class is one of ones you want to enumerate. If so, make it known to some manager class.
Check the directory in which the classes are defined to manually enumerate all classes.
Here is an implementation example of the algorigthm in the base absctract class from http://sourcemaking.com/design_patterns/template_method/php
public final function showBookTitleInfo($book_in) {
$title = $book_in->getTitle();
$author = $book_in->getAuthor();
$processedTitle = $this->processTitle($title);
$processedAuthor = $this->processAuthor($author);
if (NULL == $processedAuthor) {
$processed_info = $processedTitle;
} else {
$processed_info = $processedTitle.' by '.$processedAuthor;
}
return $processed_info;
}
I don't like it becase I think, that "showBookTitleInfo" knows too much about the methods it calls.
Here is another example
abstract class template_method {
var $state;
public function __construct() {
$this->state = 0;
}
public function processEvent( $event ) {
$this->doFirstStep( $event );
$this->doSecondStep( $event );
}
abstract public function doFirstStep( &$event );
abstract public function doSecondStep( &$event );
}
class CustomLogic extends template_method {
public function doFirstStep( &$event ) {
echo __METHOD__.": state: ".$this->state." event: $event\n";
$this->state++;
}
public function doSecondStep( &$event ) {
echo __METHOD__.": state: ".$this->state." event: $event\n";
$this->state++;
}
}
why we pass event as by-reference, if we don't change its value?
How should I implement "my steps" logic, if they are using current state, can modify its value, and other steps can read modified value and can modify it too?
For example, I want to implement cost counting mechanism for scheduled message sending - simple and reccurent(ex: every Mon, Fri until 23.05.2009).
So, I implement the algorithm in abstract class as following:
abstract class AbstractCostCounter {
public function countNotReccurentSendingCost($messageObj) {
$totalMessages = $messageObj->getTotalMessages(); // multiple recipients are allowed
$message_cost = 1; // just to give you an idea
$this->cost = $totalMessages * $message_cost;
}
abstract public function countOptional();
// I pass $messageObject not as by-reference, because it hasn't to be modified
public function countCost( $messageObject ) {
$this->countNotReccurentSendingCost( $messageObject );
$this->countOptional( $messageObject );
}
}
class TemplateNotReccurentCostCounting {
public function countOptional($messageObj) {
// do nothing
}
}
class TemplateReccurentCostCounting {
public function countOptional($messageObj) {
$notReccurentSendingCost = $this->cost;
$totalMessagesInScheduledPlan = $messageObj->getTotalMessagesInScheduledPlan();
$reccurentSendingPlanCost = $notReccurentSendingCost * $totalMessagesInScheduledPlan;
$this->cost = $reccurentSendingPlanCost;
}
}
Am I moving in the right direction?
Is it where Template method design pattern should be implemented?
Please let me know, if it is something wrong with this code.
P.S. cost counter is not a production code. I wrote it because I wanted to give you an idea.
Thanks, in advance
The template method pattern gives the parent class a lot of control, the parent class has to know a lot about the abstract methods (their signature) because it has to 'control' the algorithm. BTW the concrete method in the parent class has to be final.
You have no advantage with your firstStep secondStep methods, I could implement what I want in stepOne and do nothing in stepTwo...
The question is when would you want to use Template Method Pattern, not how to rewrite it to give more flexibility :)