Set subclass of object when parent class is constructed (dynamic sub-classes) - php

EDIT: To clear up some confusion, I am not actually using Male and Female. A better example would be parent-class Animal and sub-classes Cat and Dog.
I'm kind of new to OOP, but I've grasped it pretty well so far. However, there's one thing I can quite find a way of doing.
Firstly, I create a create a new object based around the user. The user can be be (for this example) male or female, but I cannot check if they are without checking in the database. I then need to create a new user object with the sub-class of their sex.
For example, here is my current (messy) code:
$user = new Person();
$userType = $user->GetUserType($userid);
if ($userType == 'Male') {
$user = new Male($userid);
} else {
$user = new Female($userid);
}
If I want to make a new object, I must do this every time, which is something I don't want to have to do.
Here's a little more code to help put this into perspective:
class Person {
function GetUserType($userid) {
$db = mysqlConnect();
$stmt = $db->stmt_init();
// Get the players information
$stmt->prepare("SELECT user_type FROM user_information WHERE user_id = ?");
$stmt->bind_param('i', $userid);
$stmt->execute();
$stmt->bind_result($userType);
$stmt->fetch();
$stmt->close();
$db->close();
return $userType;
}
}
class Male extends Person {
// Male based things here
}
class Female extends Person {
// Female based things here
}
So, in the __construct of the Person class, I'd like it to check for the users sex and set the appropriate sub-class.

So, in the __construct of the Person class, I'd like it to check for the users sex and set the appropriate sub-class.
Like already said elsewhere, ctors do not return, so you cannot do that. And ctors should not query the database anyway, because that would be doing work. If you cannot/want not create the correct subtype immediately via DataMapper or Repository, you can use a State Pattern:
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
This is one of the Behavioral Patterns from the Gang Of Four book. The keyword, obviously, is behavior here. The State pattern is not about varying Subtypes (Cat, Dog) as such, but rather about the difference in the behavior those have. Hence my comments to your question.
Example:
interface GenderBehavior
{
public function someBehavior();
// can add more methods here
}
class FemalePersonBehavior implements GenderBehavior
{
public function someBehavior()
{
// female specific behavior
}
}
class MalePersonBehavior implements GenderBehavior
{
public function someBehavior()
{
// male specific behavior
}
}
class UnknownGenderBehavior implements GenderBehavior
{
public function someBehavior()
{
// either implement a neutral behavior or
throw new LogicException('Unknown Gender set');
}
}
To create those instances, you add a Factory
class GenderBehaviorFactory
{
public static function create($sex = null)
{
switch ($sex) {
case 'male':
return new MalePersonBehavior;
case 'female':
return new FemalePersonBehavior;
default:
return UnknownGenderBehavior;
}
}
}
Then you add the GenderBehavior interface to the Person class and tunnel all access to the interface methods to the Behavior instance:
class Person implements GenderBehavior
{
private $behavior;
public function __construct()
{
$this->behavior = GenderBehaviorFactory::create();
}
public function changeGender($sex)
{
$this->behavior = GenderBehaviorFactory::create($sex);
}
public function someBehavior()
{
$this->behavior->someBehavior();
}
}
Now when you create a Person the first time, it will instantiate with an UnknownGenderBehavior and if you try to call someBehavior, it will raise an Exception. When you call changeGender with either male or female as argument, the appropriate GenderBehavior will be created and set to Person. And then you can call someBehavior.

You cannot choose what to return from a constructor, but you can take your hierarchy as is (Person is of unknown gender, Male and Female are known) and use something like this pattern:
public class Person {
public function ensureHasGender() {
if ($this instanceof Male || $this instanceof Female) {
return $this;
}
// now construct a Male or Female object from $this and return it
$userType = $user->GetUserType($this->userid);
return new $userType($this->userid);
}
}
So you can now call $user->ensureHasGender() as many times as you like and it will only construct a gender-specific instance the first time.
However, I think this strategy is questionable. What do you stand to gain from having separate Male and Female classes? If their behavior were so much different then this could be justified, but that doesn't sound too likely. Perhaps handling the issue internally in the class with lazy loading and appropriate conditionals would be better.

Related

Use parents child method in other child class (same parent)

I have some issues with OOP. I just started OOP in php and i have some issues.
So i have a question for you, maybe you'll help me.
I have multiple classes (in this case 3)
<?php
//FILE class.NB.php
class NB { //databse manipulations, curls
public $db;
function __construct($db) {
$this->db = $db;
}
public function LoginNB () {
//something here
$this->db->query("UPDATE logins SET login_time = %u", time());
}
}
//FILE class.fn.php
class FN extends NB {
public function deposits () {
$this->LoginNB();
return $this->db->query("SELECT * FROM deposits");
}
public function getUserWihdrawsCompared() {
// AND HERE I WOULD LIKE TO USE the DR's ::usersWithdraws
$users = $this->usersWithdraws();
}
}
//FILE class.dr.php
class DR extends NB {
public function withdraws () {
$this->LoginNB();
return $this->db->query("SELECT * FROM withdraws");
}
public function usersWithdraws() {
$a = $this->db->query("SELECT * FROM user_withdraws");
/*code here*/
return $final_array;
}
public function compare_withdraws_deposits () {
// AND HERE I WOULD LIKE TO USE the FN's ::deposits
$deposit_list = $this->deposits();
/* code here */
return $final_array;
}
}
?>
So my question is, how is possible to use everything in everywhere.
I saw something with traits but i'm not sure, how to use and what exactly to use.
My problems is what i want to user parent's child method in other child with same parent.
But in the end, i would like to use only the parent class for "runing" implementing in other classes if it's possible.
Like:
$NB = new NB($db);
$result = $NB->ShowResults();
Problem: ShowResults() should use both child's methods and child methods used in ShowResults() some times use methods from other child class.
Maybe it's impossible but i would appreciate if you could help me. (even with a confirmation that is not possible)
Thank you.
I think you haven't fully grasped what we mean by "parent" and "child" in OOP, and why they're useful. The purpose of inheritance is not to grant access to the methods of one class in another, or to automatically run multiple implementations of the same thing. Instead, the purpose is to allow code outside the classes to call one of the implementations without needing to know which one.
So, if I have an instance of class NB, I know I can call LoginNB on it. If what I'm passed is actually an instance of class FN, that will still work; class FN will either inherit that method, or reimplement it a different way, but with the same external signature.
However, class NB doesn't know anything about what classes inherit from it, any more than a function knows where else it is called from; the relationship only goes one way.

Extended class pulling through NULL - OOP

I have the following class for all my user methods:
class User {
protected $_db,
$_data;
public function __construct($user = null, $findby = 'id') {
$this->_db = DB::getInstance();
if (!$user) {
........
} else {
........
}
}
.......
public function login($username = null, $password = null) {
$user = $this->find($username, 'username');
if ($user) {
$lockdown = new Lockdown;
}
}
public function find($param = null, $method = null) {
if ($param && $method) {
$data = $this->_db->query("SELECT * FROM users ...");
if ($data->count()) {
$this->_data = $data->result();
return true;
}
}
return false;
}
public function data() {
return $this->_data;
}
}
The above is a completely stripped down version of my user class. I also have another class (lockdown) which extends user:
class Lockdown extends User {
public $getAttempts;
public function __construct() {
var_dump($this->data());
die();
}
}
However when i call the lockdown class inside of the login class, even though the data object should contain all the user information, the var_dump() is simply returning NULL.
From my calculations when the login class is called, the find method should set $_data = USER INFO, which should therefore allow the new Lockdown method invoked just after the ($this->find()) to be able to access the same data method.
I am still learning OOP Programming so don't know if there is something i am missing, but i can't seem to understand the reason as to why the Lockdown class returns NULL on the data method when it should inherit it.
You should not put any computation logic inside a constructor. It makes it hard to test. You also cannot return from a constructor.
You structure is a complete disaster. Both because of your abuse of the inheritance and of global state.
It makes no sense for a class to create a new instance of its own child class for retrieving data. This is probably a result of you attempting to for a User class to combine two different responsibilities: persistence and business logic. This constitutes a violation of Single Responsibility Principle, which then manifest in a form of a convoluted call graph.
Also the whole class Lockdown extends User construct makes no sense. The extends keyword in OOP can be translates as "is special case of" (as per LSP). The class for tracing user's login attempts is not a specialized case of "user".
You should have at least 3 separate classes for this: one for handling the "user's behavior" and other for saving/restoring "user's state" (the approach is called "data mapper"). The third one would be for managing the the failed attempts.
I would also highly recommend watching this lecture.
As for global state, instead of using a singleton anti-pattern, you should have passed the database connection as a constructor's dependency to the class, which need to interact with persistence.
As for the code, at a high level, it should probably looks something like this:
$user = new User;
$mapper = new UserMapper($db);
$user->setName($username)
if ($mapper->fetch($user)) {
if ($user->matchPassword($password)) {
// you have logged in
// add some flag in session about it
header('Location: /greetings');
exit;
}
// check the failed attempts
} else {
// no matching username
}

Dependency Injection for class with array of objects as class attribute

I am novice in OOP programming in php and trying to understand and implement the dependency injection feature in my MVC project. In the following I am explaining a super simple example of the feature where I am struggling applying the dependency injection. The actual application is lot more complex than this, however, this should be enough to demonstrate the problem I am having.
I have created a Model called “user” that is responsible for managing a single user. Data handled by the class (data about a user) is also saved in the database table. The “user” class has method to load from and save/update the data to the database table. The user class can be initiated with data loaded from the database (by using user id) or load from the array supplied to the constructor.
The project deals with multiple users at a time. So, I have created a container class called “users”. This class has an array of “user” objects. However, this class also have method to load data for multiple user objects from the database (based on criteria such as all paid users), then create the object array with the data. The number of object is created is depends on the number of users returned from the database.
The following is a sample code for the classes
class user
{
private $data;
function __construct ($arData=””)
{
$this->dbTable ="user";
if(!is_array($ar))
{
if($ar!="")
{
$ar = $this->getDataFromDB($ar);
}
else
{
$ar = array();
}
}
$this->data = $ar;
}
function getDataFromDB($id_user){ … data base implementation … }
....
Other methods
....
}
class users // the container class
{
private $objUsers;
function __ construct(){
$this->objUsers = array();
}
function loadUsers($type){
$userDataArray = $this->getUsersFromDatabase($type);
foreach($useDataArray as $userData){
$this->objUsers[] = new user($userData);
}
}
function getUsersFromDatabase($userType) { …… database …… }
…… other methods …..
}
My concern is the container class (container may not be the right word to say). I want to know the best practice to create this type of container class and what is the recommend for this. In addition, this is clearly evident that this container class is tightly coupled with “user” class and cannot be tested separately. How can I implement the dependency injection for a class like this?
As I said, I don't think this is a good fit for dependency injection. And I wouldn't set it up that way just for the sake of saying it uses dependency injection.
The main reason it's not a good fit, is that a User is always a User. So you always have a concrete contract between the wrapper, Users, and the User. You can count on User having certain methods. And you don't have some weird 3rd class that your adding into these collections, it's just a collection of a known and well defined object.
That said, I would go with a more factory style wrapper, Where the User is the simpler of the 2 classes. ( note, I didn't test any of this, so just look at it like psudo code )
class users {
public function createUser( array $data = []){
if( $data['id'] ){
$User = $this->getUser( $data['id'] );
if( $User )
return $User;
}
//depending what you want you could search on other things
//like the email, (unique) and return the user.
//you could make this as complex, or as simple as you want
//it could simply create a new user, or check for an existing one first.
return new User($data); //dependency
}
public function getUser( $id ){
$stmt = $this->DB->prepare( "SELECT * FROM users WHERE id=:id" );
$stmt->FetchMode(PDO::FETCH_CLASS, 'User');
return $stmt->fetch(); //fetch right into the class
}
public function saveUser( User $User ){
//I just added this to show how you can type hint the class
// so that it only accepts Objects of the type User
}
}
class user{
protected $id;
protected $username;
protected $email;
public function __construct(array $data = []){
foreach( $data as $field=>$value){
//this could be done better, with error checking etc.
//but I just wanted to show how you can use the setters
//dynamically when constructing with an array
//this is useful because we are not hard coding the schema of User in any files
//-note- PHP method calls are case insensitive.
$this->set{$field} = $value;
}
}
public function setId( $id ){ $this->id = $id; }
public function getId(){ return $this->id; }
public function setUsername( $username ){ $this->username = $username; }
public function getUsername(){ $this->username; }
public function setEmail( $email ){ $this->email = $email; }
public function getEmail(){ return $this->email; }
}
Then you can worry about dependency injection for things like the Database. This could be represented by having the users constructor accept a PDO or Database object. Like this
class Users{
protected $DB;
public function __construct( $DB ){
$this->DB = $DB;
}
}
The Users class doesn't care about the DB credentials, or even the particular DB driver your using. To some extent it does have some coupling with the driver based on the SQL syntax, which may be specific to a particular database. If we wanted to make this a "truer" form of dependency injection we should use an ORM like Doctrine, or some kind of Query builder ( instead of PDO itself ). Then we would have another layer of abstraction between our code and the database.
If you need user to have access to users and they cant be separated extend the class.
class users {
}
class user extends users {
}
Child user can then access the parent users properties.

PHP Factory design pattern method clarification

I want to know if this tutorial is correctly implementing factory design pattern in PHP. Below is the actual source code.
<?php
class Automobile
{
private $vehicle_make;
private $vehicle_model;
public function __construct($make, $model)
{
$this->vehicle_make = $make;
$this->vehicle_model = $model;
}
public function get_make_and_model()
{
return $this->vehicle_make . ' ' . $this->vehicle_model;
}
}
class AutomobileFactory
{
public static function create($make, $model)
{
return new Automobile($make, $model);
}
}
// have the factory create the Automobile object
$veyron = AutomobileFactory::create('Bugatti', 'Veyron');
print_r($veyron->get_make_and_model()); // outputs "Bugatti Veyron"
According to a book "Design Patterns" by Gang of Four, applicability of factory pattern is
a class can't anticipate the class of objects it must create
a class wants its subclasses to specify the objects it creates
classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate
First point, this example actually knows what class of objects to create, which is Automobile, doesn't it?
Second point, there is no subclass. Automobile class does not inherit from AutomobileFactory. I thought AutomobileFactory should have at least one function implemented by Automobile, which deals with object creations.
Can someone clarify this? I just started learning design patterns, and every time I encounter tutorials different from others, it confuses me a lot.
I pretty much agree with what is said in Wikipedia
The creation of an object precludes its reuse without significant duplication of code.
The creation of an object requires access to information or resources that should not be contained within the composing class.
The lifetime management of the generated objects must be centralized to ensure a consistent behavior within the application.
The main reason I create factories is this one I highlighted.
For example, let's imagine a real world factory with many plants throughout the country. This factory produces doors. Doors needs knobs. For logistics reasons, each one of the plants of the factory has its own knob suppliers, another completely different factory.
The production manager software of this factory will choose based on some criteria which plant will produce a lot of doors, but it does not need to know from where the knobs will come. The chosen plant will ask for its own supplier for a knob for the produced door.
However, for the client, it does not matter which plant made the door, he only cares about having his door.
Let's put this on code:
class Knob {
// something...
}
interface KnobSupplier {
public function makeKnob();
}
class SaoPauloKnobSupplier {
public function makeKnob() {
return new Knob('Knob made in São Paulo');
}
}
class NewYorkKnobSupplier {
public function makeKnob() {
return new Knob('Knob made in New York');
}
}
class Door {
public function __construct(Knob $knob) {
// something...
}
}
interface DoorFactory {
public function makeDoor();
}
class SaoPauloDoorFactory {
private $knobSupplier;
public function __construct() {
$this->knobSupplier = new SaoPauloKnobSupplier();
}
public function makeDoor() {
return new Door($this->knobSupplier->makeKnob(), "Door made in São Paulo");
}
}
class NewYorkDoorFactory {
private $knobSupplier;
public function __construct() {
$this->knobSupplier = new NewYorkKnobSupplier();
}
public function makeDoor() {
return new Door($this->knobSupplier->makeKnob(), "Door made in New York");
}
}
class ProductionManager {
private $plants = array();
// methods for adding plants, etc...
public function getDoor() {
// Somehow decides which plant will create the door.
return $plant->makeDoor();
}
}
class Client {
public function getMyDoor(ProductionManager $manager) {
return $manager->getDoor();
}
}
Using this code like:
$manager = new ProductManager();
$manager->addPlant(new SaoPauloDoorFactory());
$manager->addPlant(new NewYorkDoorFactory());
$client = new Client();
var_dump($client->getMyDoor($manager));
ProductManager does not know anything about knobs, Client does not know anything about the factory having more than one plant.
I don't really like the tutorial. As you can see in the WikiPedia page about factories ( https://en.wikipedia.org/wiki/Factory_pattern ) - it's normally done differently. The WikiPedia example does comply with the rules you mention. Check out the PHP section there.
I'm with you kidonchu, I don't really see that example as a traditional factory method pattern.
I would write your example like this (psuedo code)
<?php
abstract class CarAbstract
{
protected $_vehicleMake;
protected $_vehicleModel;
public function __construct($model)
{
$this->_vehicleModel = $model;
}
public function getMakeAndModel()
{
return $this->_vehicleMake . ' ' . $this->_vehicleModel;
}
}
class Bugatti extends CarAbstract
{
public function __construct($model)
{
parent::__construct($model);
$this->_vehicleMake = get_class($this);
}
}
class AutomobileFactory
{
public static function getInstance($make, $model)
{
if (is_file('Model/Car/' . $make . '.php')){
require_once 'Model/Car/' . $make . '.php';
$car = new $make($model);
}else{
throw new Exception('Car not found');
}
}
}
$veyron = AutomobileFactory::getInstance('Bugatti', 'Veyron');
print_r($veyron->getMakeAndModel()); // outputs "Bugatti Veyron"
There's actually a single Factory Method design pattern following the original gang of four catalog. The Abstract Factory is wholly different and is based on different structural assumptions. The Simple Factory is not a design pattern, but the what Freemans call a 'programming idiom.' The Factory method includes an abstract Creator and Product, and the Clients generally make their requests through the Creator. Specific factories are found in the ConcreteCreator(s) and the concrete products are child classes of the Product class and are instantiated by concrete creators. For a complete and simple PHP example see http://www.php5dp.com/a-simple-php-design-pattern-the-factory-method/.

How to Design Domain Layer Objects to Represent Multiple Objects & Single Object in Zend Framework?

I'm working on creating a domain layer in Zend Framework that is separate from the data access layer. The Data Access Layer is composed to two main objects, a Table Data Gateway and a Row Data Gateway. As per Bill Karwin's reply to this earlier question I now have the following code for my domain Person object:
class Model_Row_Person
{
protected $_gateway;
public function __construct(Zend_Db_Table_Row $gateway)
{
$this->_gateway = $gateway;
}
public function login($userName, $password)
{
}
public function setPassword($password)
{
}
}
However, this only works with an individual row. I also need to create a domain object that can represent the entire table and (presumably) can be used to iterate through all of the Person's in the table and return the appropriate type of person (admin, buyer, etc) object for use. Basically, I envision something like the following:
class Model_Table_Person implements SeekableIterator, Countable, ArrayAccess
{
protected $_gateway;
public function __construct(Model_DbTable_Person $gateway)
{
$this->_gateway = $gateway;
}
public function current()
{
$current = $this->_gateway->fetchRow($this->_pointer);
return $this->_getUser($current);
}
private function _getUser(Zend_Db_Table_Row $current)
{
switch($current->userType)
{
case 'admin':
return new Model_Row_Administrator($current);
break;
case 'associate':
return new Model_Row_Associate($current);
break;
}
}
}
Is this is good/bad way to handle this particular problem? What improvements or adjustments should I make to the overall design?
Thanks in advance for your comments and criticisms.
I had in mind that you would use the Domain Model class to completely hide the fact that you're using a database table for persistence. So passing a Table object or a Row object should be completely under the covers:
<?php
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();
$db = Zend_Db::factory('mysqli', array('dbname'=>'test',
'username'=>'root', 'password'=>'xxxx'));
Zend_Db_Table_Abstract::setDefaultAdapter($db);
class Table_Person extends Zend_Db_Table_Abstract
{
protected $_name = 'person';
}
class Model_Person
{
/** #var Zend_Db_Table */
protected static $table = null;
/** #var Zend_Db_Table_Row */
protected $person;
public static function init() {
if (self::$table == null) {
self::$table = new Table_Person();
}
}
protected static function factory(Zend_Db_Table_Row $personRow) {
$personClass = 'Model_Person_' . ucfirst($personRow->person_type);
return new $personClass($personRow);
}
public static function get($id) {
self::init();
$personRow = self::$table->find($id)->current();
return self::factory($personRow);
}
public static function getCollection() {
self::init();
$personRowset = self::$table->fetchAll();
$personArray = array();
foreach ($personRowset as $person) {
$personArray[] = self::factory($person);
}
return $personArray;
}
// protected constructor can only be called from this class, e.g. factory()
protected function __construct(Zend_Db_Table_Row $personRow) {
$this->person = $personRow;
}
public function login($password) {
if ($this->person->password_hash ==
hash('sha256', $this->person->password_salt . $password)) {
return true;
} else {
return false;
}
}
public function setPassword($newPassword) {
$this->person->password_hash = hash('sha256',
$this->person->password_salt . $newPassword);
$this->person->save();
}
}
class Model_Person_Admin extends Model_Person { }
class Model_Person_Associate extends Model_Person { }
$person = Model_Person::get(1);
print "Got object of type ".get_class($person)."\n";
$person->setPassword('potrzebie');
$people = Model_Person::getCollection();
print "Got ".count($people)." people objects:\n";
foreach ($people as $i => $person) {
print "\t$i: ".get_class($person)."\n";
}
"I thought static methods were bad
which is why I was trying to create
the table level methods as instance
methods."
I don't buy into any blanket statement that static is always bad, or singletons are always bad, or goto is always bad, or what have you. People who make such unequivocal statements are looking to oversimplify the issues. Use the language tools appropriately and they'll be good to you.
That said, there's often a tradeoff when you choose one language construct, it makes it easier to do some things while it's harder to do other things. People often point to static making it difficult to write unit test code, and also PHP has some annoying deficiencies related to static and subclassing. But there are also advantages, as we see in this code. You have to judge for yourself whether the advantages outweigh the disadvantages, on a case by case basis.
"Would Zend Framework support a Finder
class?"
I don't think that's necessary.
"Is there a particular reason that you
renamed the find method to be get in
the model class?"
I named the method get() just to be distinct from find(). The "getter" paradigm is associated with OO interfaces, while "finders" are traditionally associated with database stuff. We're trying to design the Domain Model to pretend there's no database involved.
"And would you use continue to use the
same logic to implement specific getBy
and getCollectionBy methods?"
I'd resist creating a generic getBy() method, because it's tempting to make it accept a generic SQL expression, and then pass it on to the data access objects verbatim. This couples the usage of our Domain Model to the underlying database representation.

Categories