php prevent parent from accessing child properties - php

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.

Related

How to access parent class from child class?

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);
}

Traverse a class tree without overriding methods?

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.

How to cast an array of Objects

I'm trying to cast an array of Objects for a week already in a PHP class and have had some real issues making it to work and mainly with the logic itself as I am new to classes. Looked and read a lot of resources but it does not seem to make any sense to me, any pointers would be greatly appreciated and I am open to suggestions.
The issue:
Create a PHP class as part of the project named Contact, and then a class called 'ContactList' that contains an array of these contact objects.
And next, an array of ContactList objects called 'ContactTabs'.
Then, in the program, populate one ContactList object (named 'Contacts') with the current contacts, and create a new ContactList object named 'Friends', and add some names and email addresses there for friends. It is most important that this be done in a nice, object-oriented fashion so it can allow to create other type of contacts in the future.
A 'ContactList' object, should contain not only an array that is the list of contacts, but it would also contain the text label to put on the tab. So, it is more appropriate that the ContactList be more than a simple array, but rather it should be an object that contains an array as well as a text label.
The business logic is the following:
Contact
name
bgcolor
lgcolor
email
ContactTabs
Employees
Friends
// class definition
class Contact{
// define properties
public $name;
public $bgcolor;
public $lgcolor;
public $email;
// constructor
public function __construct() {
}
//destructor
public function __destruct() {
}
}
class ContactList extends Contact {
// constructor
public function __construct($contactname,$contactbgcolor,$contactlgcolor,$contactemail) {
$this ->name = $contactname;
$this ->bgcolor = $contactbgcolor;
$this ->lgcolor = $contactlgcolor;
$this ->email = $contactemail;
parent::__construct();
}
}
$johndie = new ContactList('John Die','#FCEDC9','#FEF9ED','somecontact1#gmail.com','9');
$johndoe = new ContactList('John Doe ','#DEEDFE','#EDF5FE','somecontact2#hotmail.com,'6');
$Friends = new ExtendedArrayObject($jp);
$Employees = new ExtendedArrayObject($elvete);
$ContactTabs= new ExtendedArrayObject($Employees,$Friends);
print_r($ContactTabs);
You had the Contact class correct (although you may want to use private/protected properties for encapsulation, but you can change that later).
This is how I would do it:
class Contact{
public $name;
public $bgcolor;
public $lgcolor;
public $email;
public function __construct($name, $bgcolor, $lgcolor, $email) {
$this->name = $name;
$this->bgcolor = $bgcolor;
$this->lgcolor = $lgcolor;
$this->email = $email;
}
}
class ContactList implements Iterator, ArrayAccess {
protected $_label;
protected $_contacts = array();
public function __construct($label) {
$this->_label = $label;
}
public function getLabel() {
return $this->label;
}
public function addContact(Contact $contact) {
$this->_contacts[] = $contact;
}
public function current() {
return current($this->_contacts);
}
public function key() {
return key($this->_contacts);
}
public function next() {
return next($this->_contacts);
}
public function rewind() {
return reset($this->_contacts);
}
public function valid() {
return current($this->_contacts);
}
public function offsetGet($offset) {
return $this->_contacts[$offset];
}
public function offsetSet($offset, $data) {
if (!$data instanceof Contact)
throw new InvalidArgumentException('Only Contact objects allowed in a ContactList');
if ($offset == '') {
$this->_contacts[] = $data;
} else {
$this->_contacts[$offset] = $data;
}
}
public function offsetUnset($offset) {
unset($this->_contacts[$offset]);
}
public function offsetExists($offset) {
return isset($this->_contacts[$offset]);
}
}
And ContactTabs would be very similar to ContactList, but would accept ContactList objects instead of Contact.
How it would work is:
// create some contacts
$bob = new Contact('Bob', 'black', 'white', 'bob#bob.com');
$john = new Contact('John', 'black', 'white', 'john#john.com');
// create a contact list and add contacts to it
$contactlist = new ContactList('Contacts');
$contactlist->addContact($bob); // using a method
$contactlist[] = $john; // using array notation
// access the list by using foreach on it, since ContactList implements Iterator
foreach ($contactlist as $contact) {
echo $contact->email;
}
First step will be to throw out all that code and start fresh. I don't know what "ExtendArrayObject" is, but you don't need it for this - it only complicates things. The rest of the code is not really on the right track.
In OOP, a class is supposed to model "something." Some kind of entity, which is often, but not always, a real-world thing. The first step in OO development is to sketch out the entities involved and model them in classes. In this case, your assignment tells you exactly what the entities are:
Contact
ContactList
So, OK, what do we need to know about our contact - what properties do we need it to have? Let's say "name" and "email." Let's give it these properties then:
class Contact {
public $name;
public $email;
}
A ContactList sounds pretty simple, it's just a list of Contacts, with a title that can be displayed in a tab. I'll write it so that it stores its Contacts internally in an array:
class ContactList {
public $title;
public $contacts = array();
}
You may be wondering, why do I need a ContactList if all it does is hold a title and store Contacts in an array? The answer is, because your assignment says you need it. :) Like many aspects of OOP, their usefulness will only be revealed as your projects increase in complexity. Just go along with it for now.
Now, put these classes in 2 separate files: Contact.php and ContactList.php. (This is not strictly necessary but is generally considered best practice.) Create a 3rd file called whatever, and in it, add the following code to tie it all together:
include("Contact.php");
include("ContactList.php");
// create a Contact object
$contact = new Contact();
$contact->name = "Bill";
$contact->email = "bill#gmail.com";
// create a ContactList object
$contact_list = new ContactList();
// set its title
$contact_list->title = "My Great Contacts";
// add our contact to it
$contact_list->contacts[] = $contact;
print_r($contact_list);
With this code, you are 80% of the way there - I didn't want to do exactly what your assignment specified because that would leave nothing left for you! I encourage you to play around with this until you feel like you really "get it." It often takes a while for OOP to "click" in one's head. But it's really crucial.
Exercises:
Add some different properties to the Contact class, like "phone" and "address"
Create some more contacts and add them to the list
Create a second ContactList object, containing a different list, with different contacts in it
Extra credit: Write a method in ContactList that adds a Contact, but only if another one with the same email address doesn't already exist in the list.

A PHP design pattern for the model part [PHP Zend Framework]

I have a PHP MVC application using Zend Framework. As presented in the quickstart, I use 3 layers for the model part :
Model (business logic)
Data mapper
Table data gateway (or data access object, i.e. one class per SQL table)
The model is UML designed and totally independent of the DB.
My problem is : I can't have multiple instances of the same "instance/record".
For example : if I get, for example, the user "Chuck Norris" with id=5, this will create a new model instance wich members will be filled by the data mapper (the data mapper query the table data gateway that query the DB). Then, if I change the name to "Duck Norras", don't save it in DB right away, and re-load the same user in another variable, I have "synchronisation" problems... (different instances for the same "record")
Right now, I use the Multiton / Identity Map pattern : like Singleton, but multiple instances indexed by a key (wich is the user ID in our example). But this is complicating my developpement a lot, and my testings too.
How to do it right ?
Identity Map
Edit
In response to this comment:
If I have a "select * from X", how can I skip getting the already loaded records ?
You can't in the query itself, but you can in the logic that loads the rows into entity objects. In pseudo-code:
class Person {}
class PersonMapper {
protected $identity_map = array();
function load($row) {
if (!isset($this->identity_map[$row['id']])) {
$person = new Person();
foreach ($row as $key => $value) {
$person->$key = $value;
}
$this->identity_map[$row['id']] = $person;
}
return $this->identity_map[$row['id']];
}
}
class MappingIterator {
function __construct($resultset, $mapper) {
$this->resultset = $resultset;
$this->mapper = $mapper;
}
function next() {
$row = next($this->resultset);
if ($row) {
return $this->mapper->load($row);
}
}
}
In practice, you'd probably want your MappingIterator to implement Iterator, but I skipped it for brevity.
Keep all loaded model instances in "live model pool". When you load/query a model, first check if it has been already loaded into pool (use primary key or similar concept). If so, return the object (or a reference) from pool. This way all your references point to the same object. My terminology may be incorrect but hopefully you get the idea. Basically the pool acts as a cache between business logic and database.
Multiton
Best option if you want to use a variety of singletons in your project.
<?php
abstract class FactoryAbstract {
protected static $instances = array();
public static function getInstance() {
$className = static::getClassName();
if (!(self::$instances[$className] instanceof $className)) {
self::$instances[$className] = new $className();
}
return self::$instances[$className];
}
public static function removeInstance() {
$className = static::getClassName();
if (array_key_exists($className, self::$instances)) {
unset(self::$instances[$className]);
}
}
final protected static function getClassName() {
return get_called_class();
}
protected function __construct() { }
final protected function __clone() { }
}
abstract class Factory extends FactoryAbstract {
final public static function getInstance() {
return parent::getInstance();
}
final public static function removeInstance() {
parent::removeInstance();
}
}
// using:
class FirstProduct extends Factory {
public $a = [];
}
class SecondProduct extends FirstProduct {
}
FirstProduct::getInstance()->a[] = 1;
SecondProduct::getInstance()->a[] = 2;
FirstProduct::getInstance()->a[] = 3;
SecondProduct::getInstance()->a[] = 4;
print_r(FirstProduct::getInstance()->a);
// array(1, 3)
print_r(SecondProduct::getInstance()->a);
// array(2, 4)

Object Oriented Programming, extending properties

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.

Categories