I'm trying to automate a form validation and db insertion process. In a particular part, I need to be able to access the parent class from the child class. To be exact, I need to access the parent class to access another child class.
I've tried to replicate the same structure I'm using in the actual code:
class Family {
public function __construct($members = []) {
foreach ($members as $member) {
$this->$member[0] = new Member($member);
}
}
}
class Member {
public $name;
public $niisan;
public function __construct($name = []) {
$this->name = $name[0];
if (count($name) > 1) {
$this->get_niisan($name[1]);
}
}
public function get_niisan($member_lookup) {
$this->niisan = $this->name . " has a niisan named X";
}
}
$Winchesters = new Family([
["Dean"],
["Sam", "Dean"],
]);
Output:
object(Family)#1 (2) {
["Dean"] => object(Member)#2 (2) {
["name"] => "Dean"
["niisan"] => NULL
}
["Sam"] => object(Member)#3 (2) {
["name"] => "Sam"
["niisan"] => "Sam has a niisan named X"
}
}
What I want to do is create two subclasses in the main class. Order of the creation of subclasses matters. ["Sam"] is dependant on ["Dean"], so ["Dean"] needs to be created first. Some of the properties of ["Dean"] will be used in ["Sam"].
In JavaScript, I'd write it like this:
function Family(members) {
var parent = this; // Family object
for (var i = 0; i < members.length; i++) {
// passing a reference of Family to the new Member object
// so that it can access the main object later
this[members[i][0]] = new Member(parent, members[i]);
}
}
function Member(parent, name) {
// saving the reference to the parent object
this.parent = parent;
this.name = name[0];
this.niisan = "";
this.get_niisan = function (lookup) {
// accessing the parent object and then getting the name property of "Dean" object
this.niisan = this.name + " has a niisan named " + this.parent[lookup].name;
};
if (name.length > 1) {
this.get_niisan(name[1]);
}
}
var Winchesters = new Family([
["Dean"],
["Sam", "Dean"]
]);
Passing the main object to each sub-object. PHP must have its own way to deal with this. I just don't know it.
Update: For the down/close-voter: How is this unclear?
I have two classes: Family and Member. Member class is initialized inside the Family class. Following code
$Winchesters = new Family([
["Dean"],
["Sam", "Dean"],
]);
results in:
object(Family)#1 (2) {
["Dean"] => object(Member)#2 (2) {
["name"] => "Dean"
["niisan"] => NULL
}
["Sam"] => object(Member)#3 (2) {
["name"] => "Sam"
["niisan"] => "Sam has a niisan named X"
}
}
At runtime, first a Member with the name "Dean" is created and assigned to a variable Dean inside Family.
Second, Member "Sam" is created, but Sam is dependant on the first created object, Dean. Sam needs to access the parent class Family, and then access to Dean, and get the property name and use it in assigning niisan variable.
Please check the JavaScript example. I want to mimic the exact functionality in PHP. Pass the main class to the child class so that the child class can access the later-created variables inside the main class.
In a particular part, I need to be able to access the parent class
from the child class. To be exact, I need to access the parent class
to access another child class.
You can't access another child class from a parent class. Only the child can access the parent. In your example, you haven't created any kind of inheritance. This is how you create inheritance in PHP.
class FooParent {
public function display($text) {
echo $text;
}
}
class Foo extends FooParent {
public function someMethod() {
// ask the parent to display the text
parent::display("Hello World!");
}
}
$foo = new Foo();
$foo->someMethod();
Which would display "Hello World!". Hopefully this will help you get started, to learn more about PHP's version of OOP - http://php.net/manual/en/language.oop5.php
Your terminology is confusing. In PHP OOP, parent and child usually refer to relationships between classes that inherit from each other, not the objects of those classes (C++ calls them base and derived class, and Javascript uses prototype chains for parent classes).
What you need to do is store a reference to the Family in the Member class.
class Member {
public $name;
public $niisan;
public $family;
public function __construct($name = [], $family) {
$this->family = $family;
$this->name = $name[0];
if (count($name) > 1) {
$this->get_niisan($name[1]);
}
}
public function get_niisan($member_lookup) {
$this->niisan = $this->name . " has a niisan named X";
}
}
class Family {
public function __construct($members = []) {
foreach ($members as $member) {
$this->$member[0] = new Member($member, $this);
}
}
}
Then if the Member class wants to access siblings, it can use $this->family to get the containing family.
BTW, using variable-named properties in Family is poor design, IMHO. Instead, you should use a single $member property containing an associative array:
$this->members = array();
foreach ($members as $member) {
$this->members[$member[0]] = new Member($member, $this);
}
Related
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.
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.
the question is simple. I have a base abstract class (person). From this i have extended another class (patients).
I save personal information (e.g. firstname, lastname) in PERSONS table [there is an ADD function. ]. Patient specific information (like illness, medicines, ...) are saved into a separate PATIENTS class. [there is an ADD function that calls the parent, then some code].
How do I prevent person's add function from accessing properties defined inside it's child, patients?
In order to make it more clear, here is a sample code:
class P {
public P_var = 'Anoush' ;
public function add ()
{
// find all properties:
foreach ($this as $prop => $val )
{
$insertables [$prop] = $val ;
}
// insert all VALUES FIELDSET etc. based on the array created above
}
class CH extends P {
public CH_var1 = 'ravan' ;
public CH_var2 = 'something' ;
}
Then when I call add, the $insertables will contain P_var, CH_var1 , CH_var2. I only want it to have P_var.
Thanks
You can do this by using Reflection (see http://www.php.net/manual/en/book.reflection.php).
class Parent {
public function add() {
$insertables = $this->_getOwnProperties(__CLASS__);
// ...
}
protected function _getOwnProperties($className) {
$reflection = new ReflectionClass($this);
$props = array();
foreach ($reflection->getProperties() as $name => $prop) {
if ($prop->class == $className) {
$props[$name] = $prop;
}
}
return $props;
}
}
However, I recommend refactoring your code instead to get a cleaner solution (e.g. add a method getProperties() (maybe defined by an interface) or whatever. Then let your database class invoke that function in order to get the list of properties to store in the database.
I know that PHP5 will let you iterate through a class's properties. However, if the class extends another class, then it will include all of those properties declared in the parent class as well. That's fine and all, no complaints.
However, I always understood SELF as a pointer to the current class, while $this also points to the current object (including stuff inherited from a parent)
Is there any way I can iterate ONLY through the current class's properties. Reason why I'm asking this.... I'm using CI and iterating through $this includes tons of parent properties that I don't need.
<?php
class parent
{
public $s_parent = "Parent sez hi!";
public $i_lucky_number = 6;
}
class child extends parent
{
public $s_child = "Child sez hi!";
public $s_foobar = "What What!!";
public $i_lucky_number = 7;
public iterate()
{
foreach ($this as $s_key => $m_val)
{
echo "$s_key => $m_val<br />\n";
}
}
}
$o_child = new child();
$o_child->iterate()
The output is
s_parent => Parent sez hi!
s_child => Child sez hi!
s_foobar => What What!!
i_lucky_number => 7
I DON'T Want to see "s_parent => Parent sez hi!"
I just want to iterate through the current class's properties. Not those inherited elsewhere.
Thanks in advance.
Using the Reflection methods, you could do the following:
public function iterate()
{
$refclass = new ReflectionClass($this);
foreach ($refclass->getProperties() as $property)
{
$name = $property->name;
if ($property->class == $refclass->name)
echo "{$property->name} => {$this->$name}\n";
}
}
Ok this is not just a PHP question, but I have this problem in PHP so I will post the example in PHP.
Example:
I have three classes, say, data_abstract, person, and student. Now, I have one array of data related to each of those objects.
class person extends data_abstract
{
protected $data; //name, gender, etc
}
class student extends person
{
protected $data; //student_id, etc
}
Now, assuming each of those "data" property is from database tables, for example, table_person, table_student.
Upon instantiation, we will parse the class name by get_class() function, and get data from their related tables.
class data_abstract
{
public function __construct()
{
$name = get_class($this);
$table = 'table_' . $name;
$this->data = DB->query('SELECT * FROM ' . $table);
//whatever DB constant is,
//I'm just trying to get all rows of data from the related table.
}
}
Ok, now the problem, when I instantiate student by $student = new student(); the constructor will get data from table_student for me and put it in $student->data, but I won't be able to get the data from table_person and put those two sets of data into one object.
By extending another class, we can have all the methods (functions) extended and customized (via polymorphism), but extending the attributes/properties of each level of object seems to be hard, at least without some manual construction.
Is there any way in the abstraction level to achieve this?
(thanks for reading, wish I could've made the question clearer.)
If I understand well :
you want all your DB data in $data;
$data must be feed with data from the table 'table_classname';
$data "inherit" from $data that should have been loaded in parents class with that process.
In that case, you should externalize $data feeding so you can overload the data feeding. I edited, now we have a working example :
class DataAbstract // Using caps is much better for class name
{
public function __construct()
{
$this->loadData();
}
public function loadData()
{
// don't use getclass on $this or $this will refer to the children
$table = 'table_' . __CLASS__;
$this->data = array($table);
}
}
class Person extends DataAbstract
{
public function __construct()
{
parent::__construct();
}
public function loadData()
{
parent::loadData();
$table = 'table_' . __CLASS__;
$this->data = array_merge($this->data, array($table));
}
}
class Student extends Person
{
public function __construct()
{
parent::__construct();
}
public function loadData()
{
parent::loadData();
$table = 'table_' . __CLASS__;
$this->data = array_merge($this->data, array($table));
}
}
$c = new student();
print_r($c->data);
Outputs
Array
(
[0] => table_DataAbstract
[1] => table_Person
[2] => table_Student
)
BTW, remember that PHP got introspection, it allows you you to set the fields you need dynamically : maybe cleaner that using a big Array.
Provided you know all the fields names, you can do something like
function populate($data) // get the array from the DB
{
$fieldList = get_class_vars($this); // get the filed list
foreach ($fieldList as $key => $value)
{
$this->$key = $data[$key]; // feed the field one by one with the array
}
}
Personally, I would put the database loading class in an protected method that takes the attribute $tablename, and which loads all the data. Then in the constructor of the class call it by hand, and the parent.
class Person
{
public function __construct() {
$this - > loadData("Person");
}
}
Class Student extends Person
{
public function __construct() {
parent::__construct();
$this - > loadData("Student");
}
}
Now, when you construct Student both data from Student and Person is loaded. if you use array_merge() the 2 data arrays will be merged into one.
It's a matter of style; some people would critisise this by saying that you are now repeating something twice - more work to refactor - but I would say you are decoupling the class names and interfaces from the database design (a good thing) and with the parent call, the code is now more OO.