<?php
/*
* class: C_QUESTION_MULTIPLE_CHOICE_SINGLE_ANSWER
* properties:
* functions:
*/
class C_QUESTION_MULTIPLE_CHOICE_SINGLE_ANSWER extends C_QUESTION {
protected $q_type = 'T_MULTIPLE_CHOICE_SINGLE_ANSWER';
protected $q_type_info;
/*
* $choices:
* choices['A'] = array(answer = 'Y', description = '')
* choices['B'] = array(answer = 'N', description = '')
*/
protected $choices;
public $output_info = '';
public $count = 0;
function __construct($q_content, $option = 'load') {
// call parent's construct function to handle question base class information
// in parent construct function, it will call parent's load or save function by itself.
parent::__construct($q_content, $option);
if (! $this->op_status) {
// call function failed
return;
}
// handle multiple choice part
switch ($option) {
case 'save':
// $option = false, don't call parent::save() function
// parent construct function will call parent save function
$this->save($q_content, false);
break;
}
} // end of construct function
function save($q_content, $option = true) {
$this->count++;
$this->output_info .= '</br>'.$this->count.'</br>';
} // end of save function
}
In the above code, the sub-class function save is performed twice. If I don't call parent construct function:
/* don't call parent construct function
parent::__construct($q_content, $option);
if (! $this->op_status) {
// call function failed
return;
}
*/
The function save() will be performed once.
In the parent construct function, the parent class QUESTION will cal it's own save() function. The sub-class C_QUESTION_MULTIPLE_CHOICE_SINGLE_ANSWER override the parent function save(). So in the sub-class construction function, I manually call parent::__construct() function. But I don't why the sub-class save() function is called twice. I debug this by sub-class properties
public $output_info = '';
public $count = 0;
Please help me.
Thanks a lot.
=========================================================================================
I debuged several times after post the above question, found:
parent class QUESTION: __construct() function:
function __construct($q_content, $option = 'load') {
// set the operation status to true. If this operation fails, this will be set to false
$this->op_status = true;
switch ($option) {
case 'load':
if (!$q_content['qid']) {
$this->op_status = false;
drupal_set_message(t('question id :qid not exist. Please contact site administrator!', array(':qid' => $q_content['qid'])), 'error');
break;
}
$this->basic['qid'] = $this->extra['qid'] = $q_content['qid'];
$this->load($this->basic['qid']);
break;
case 'save':
**//$this->save($q_content);
self::save($q_content);**
break;
}
}
if I use $this->save to call parent itself save function, this statement not only call parent::save function, but also will call sub class::save function. It's very funny and confuse.
If I use self::save statement in the parent class QUESTION, then it won't call sub class::save function.
My question is, since I've already overrided parent::save function in the sub class, I should call parent::save, then call $this->save in the sub-class do something for subclass. Why when I call parent::save, it will perform both parent::save and sub-class::save. It really confuse me.
I tried to find answer in the php manual and internet, but I didn't find the relevant article can make me clear. They only say, self::function() is used for the static member function, and $this->function() is used for other member and function. But my function and member are not static. Or the default function and member are static?
Really appreciate for who can help me.
Thanks a lot.
In php OOP, $this-> referrer to the current instant of the class, whereas self:: referrer to the class where self:: is declared.self:: is also use to referrer to static functions and properties.
So, in your case, you have to change the call to your parent's save() function as self::save() within the parent's construct function.
Also, within your child class, you can call $this->save() to call the save function of the child, because you are overriding the parent's save function.you can also use self::save() within the child class.if you want to call parent's save function from a child class then you can use parent::save() in your child class.
No, default functions aren't static.to make them static you have to add static keyword in front of the function declaration.note that you can't declare __construct(),__deconstruct() as static.
Since your functions aren't static, when you referrer to them as self:: you are referring to the current class.it's called Scope Resolution Operator (::). also read this SO answer
Related
I'm building an API service and have a parent class:
classAPI {
public responseCode = "";
public responseMessageLog ="";
function run{
// here I call my user auth class
$oUser = new classUser(...);
}
}
Inside my classUser I do a bunch of stuff and then write a bunch of variables: responseMessageLog (which is running log of where the script went) and responseCode (which is set to 0 or 1 or whatever depending on success or failure or warning).
I need to access my responseCode and responseMessageLog variables from within my User class and my parent API class, but I don't really want to be passing these variables into each child class and then passing them back. I would like it that when I update the variable in the child class it updates everywhere in all my class.... kind of like a global variable would... but I know that's not a good idea.
How have others stopped passing variables down the rabbit trail of classes.
in this class I
Passing dependencies isn't a rabbit hole you want to avoid--it makes for more testable code. However, you don't need to pass every property, you can pass the parent object.
In your case just pass the classAPI object into the constructor of the classUser and in the constructor assign it to property. The classAPI properties are public so you can access them in an instance of classUser.
ClassAPI {
public $responseCode = "";
public $responseMessageLog ="";
public function run{
// here I call my user auth class
$oUser = new ClassUser($this, ...);
}
}
ClassUser {
public $myClassApi = null;
public function __construct(ClassAPI $myClassApi) {
$this->myClassApi = $myClassApi;
}
public function someFunction() {
echo $this->myClassApi->responseCode;
}
}
Added notes:
In case it comes up in another answer, don't use static properties to do what you're trying to do.
Capitalize your class names.
In production code I might add an initialization function in ClasUser instead passing the ClassAPI directly into the constructor.
Basically I have a method which I need to run when the constructor is finished (the method is called persist() and it simply saves a key which was generated during the constructor into the session). It seems simple enough, and it works - at the end of __construct I make the call to $this->persist().
The problem is that this class is subclassed many times. This causes two issues.
One, that I must remember to make the call to persist() at the end of every single subclass's __construct method. Not a huge issue but it doesn't feel very OOP, I feel like I could be dealing with this in the parent class some how and that this would be better.
Two, if a subclass is subclassed (which it is), and the __construct methods chained (i.e. parent::__construct called), the persist() method will be getting fired multiple times, once for each time the class has been subclassed. It only needs to be called once, when all construction is complete. In this scenario it doesn't really break anything because when the persist method is called for the 2nd, 3rd time etc., it simply overwrites what was persisted before. But that isn't the point, because I just feel like there must be a better way and that there are scenarios out there that would not allow for the method to be called multiple times.
Is a factory method which constructs the object and then makes the call to persist on it the only way? I can go down this route but I am just wondering if there is a way to do it without, so that the method from the parent is always called after construction.
Here is some example code:
session_start();
is(!isset($_SESSION["Component"])) $_SESSION["Component"] = [];
abstract Class Component
{
private $id;
protected $key;
function __construct($id = NULL)
{
$this->id = $id;
$this->key = [];
$this->key["something"] = "SomeValue";
$this->persist(); // First call
}
protected function persist()
{
if($this->id !== NULL) $_SESSION["Component"][$this->id] = $this->key;
}
}
Class SomeComponent extends Component
{
function __construct($id = NULL)
{
parent::__construct($id);
$this->key["something-else"] = "SomeOtherValue";
$this->persist(); // Second call
}
}
Class SomeSpecialistComponent extends SomeComponent
{
function __construct($id = NULL, $key = [])
{
parent::__construct($id);
$this->key = array_merge($this->key, $key);
$this->persist(); // Third call
}
}
$my_component = new SomeSpecialistComponent(1, ["example" => true]);
Only trick I found to get something similar (except I wanted to execute things before and not after) is using a parent class with an abstract method as a new constructor :
abstract class RequireThings {
public function __construct() {
$this->constructAndPersist();
$this->persist();
}
abstract function constructAndPersist();
// You could also set this function in your children classes by the way.
public function persist() {
echo ' Then I persist!';
}
}
class UsingPersist extends RequireThings {
public function constructAndPersist() {
echo 'I do my things first.';
}
}
$class = new UsingPersist();
Would output :
I do my things first. Then I persist!
If I got your problem right, it should be enough to avoid problems you are facing.
The main downside of this solution is that you have to use a new function which is supposed to be your new constructor for this type of classes. That's why I set the __constructPersist as abstract, it forces the behavior as wanted.
I would argue in favor of the factory method, mostly because you're doing real work in the constructor. Remove the call where work is being done in the constructors ($this->persist) and place it in the factory:
class ComponentFactory
{
const SOME_COMPONENT = 'component';
const SOME_SPECIALIST_COMPONENT = 'specialist_component';
public static function make($type, $id, $key = null)
{
switch($type) {
case self::SOME_COMPONENT:
$component = new SomeComponent($id);
break;
case self::SOME_SPECIALIST_COMPONENT:
$component = new SomeSpecialistComponent($id, $key);
break;
}
$component->persist();
return $component;
}
}
$component = ComponentFactory::make(ComponentFactory::SOME_COMPONENT, 42);
$specialist = ComponentFactory::make(
ComponentFactory::SOME_SPECIALIST_COMPONENT,
43,
[
'something' => 'SomeValue',
'something-else' => 'SomeOtherValue',
]
);
According to Miško Hevery (author of AngularJS and agile coach at Google) these are the warning signs of doing too much work in the constructor:
new keyword in a constructor or at field declaration
Static method calls in a constructor or at field declaration
Anything more than field assignment in constructors
Object not fully initialized after the constructor finishes (watch
out for initialize methods)
Control flow (conditional or looping logic) in a constructor
CL does complex object graph construction inside a constructor
rather than using a factory or builder
Adding or using an initialization block
just create another function that you'll call before $this->persist and override that in your subclasses instead of the constructor
Please explain execution flow of the below statement
$this->setPageID()
->paginate()
->sendCacheHeaders();
in below code
protected function main()
{
$this->setPageID()
->paginate()
->sendCacheHeaders();
}
public function setPageID()
{
$this->pageID = (int)$this->Router->getRealPageID();
return $this;
}
protected function paginate()
{
d('paginating with $this->pagerPath: ' . $this->pagerPath);
$Paginator = Paginator::factory($this->Registry);
$Paginator->paginate($this->Cursor, $this->PER_PAGE,
array('currentPage' => $this->pageID,
'path' => '{_WEB_ROOT_}/' . $this->pagerPath));
$this->pagerLinks = $Paginator->getLinks();
return $this;
}
protected function sendCacheHeaders()
{
return $this;
}
What is the flow of this methods execution?, Is there any data transfer/communication b/w these methods?
I call this chaining. Basically, your functions are part of a class and that class has an instance ($class = new class()).
Your functions are returning that instance. While not a best practice per se, it does mean that you can chain the calls back to back.
$this->setPageID() ->paginate() ->sendCacheHeaders();
Note how each function returns $this. So it's the same as writing
$this->setPageID();
$this->paginate();
$this->sendCacheHeaders();
They're not communicating with each other explicitly. They all belong to the same class instance so they can access any variables belonging to that class (or any parent classes). So when paginate() sets $this->pagerLinks, any function in that class can access that value.
$this
->setPageID() // sets class variable $pageID from Router class. Returns current class.
->paginate() // Setup of Paginator class, assigns links to $pagerLinks. Returns current class
->sendCacheHeaders(); // does nothing. Returns current class
Because every function return $this so it's possible to chain method calls. Without returning $this your call will look like this:
$this->setPageID();
$this->paginate();
$this->sendCacheHeaders();
I am working on an OOP implementation and I have the following:
abstract class Parent{
public abstract function select($order="desc");
}
class Child extends Parent{
public function select($order) // here is the problem error
{
// selection code
}
}
This throws an error that tells me the declaration must be compatible with the parent method.
I did implement it with the right parameters except I didn't carry over the default parameter setting.
I do not want to copy past the same prototype of parent method in 100 classes if i want someday change the default value. How can I do this?
does generic exist in php ??
public abstract function select($order="desc");
and public function select($order) dont match.
remove the default value from the abstract function.
About the only way I can see to avoid updating a lot of values if you ever want to change the common default is this:
abstract class Parent{
const DEFAULT_SELECT_ORDER = "desc";
public abstract function select($order = "");
protected static function select_order(&$order)
{
if (empty($order) || !in_array(strtolower($order), array("asc", "desc"))) {
// additional test to check if the value is valid
$order = self::DEFAULT_SELECT_ORDER;
}
}
}
class Child extends Parent{
public function select($order = "") // here is the problem error
{
self::select_order($order);
// selection code
}
}
Hmm - another, probably better approach:
abstract class Parent {
protected $order = "desc";
public function order($order) {
if (in_array(strtolower($order), array("asc", "desc"))) {
$this->order = $order;
} else {
// probably should throw an exception or return false or something
}
return true;
}
public abstract function select();
}
class Child extends Parent {
public function select() {
// select code using $this->order
}
}
$query = new Child();
$query->order("asc");
$results = $query->select();
All you need to do is change your extended method to be something like:
public function select($order="some other value") // here is the problem error
{
// selection code
}
Essentially because the original method has a default value then ALL overrides must have a default value.
In order to do what you want you would have to make $order an object property of Parent and change the method signature to get rid of the $order parameter. Then within any specific implementation you could simply set $order to whatever else you want.
You possible could use my tiny library ValueResolver, for example:
$myVar = ValueResolver::resolve($var, $default);
and don't forget to use namespace use LapaLabs\ValueResolver\Resolver\ValueResolver;
There are also ability to typecasting, for example if your variable's value should be integer, so use this:
$id = ValueResolver::toInteger('6 apples', 1); // returns 6
$id = ValueResolver::toInteger('There are no apples', 1); // returns 1 (used default value)
Check the docs for more examples
we have a problem [cit.]
I need to assign a callback dynamically within a class, in base of a variable param: my goal is to have just one class (and not a main class and many extender sub-class), and inside this class if a value is X, then the funcitonX must be used, if is Y, the functionY.
I know i cant explain well, i hope my example will do:
class plzComplicateMyLife{
public $vehicle;
public $kindVehicle;
public $dynamicFunction;
public function __construct($vehicle, $kindVehicle){
$this->kindVehicle = $kindVehicle;
$this->vehicle = $vehicle;
switch($kindVehicle){
case 'cycle':
$this->dynamicFunction = "isACycle";
break;
case 'car':
$this->dynamicFunction = "isACar";
break;
}
//here come the problem, i need to call the callback store in dynamicFunction.
//i tried:
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//error: Catchable fatal error: Object of class plzComplicateMyLife could not be converted to string in [...]
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//Warning: call_user_func(plzComplicateMyLife::isACar) [function.call-user-func]: First argument is expected to be a valid callback in [...]
//$this->dynamicFunction();
//Fatal error: Call to undefined method plzComplicateMyLife::dynamicFunction() in [...]
//so, how can i do that?
}
public function isACycle($vehicle){
echo 'im a cycle, model: '.$vehicle.'<br />';
}
public function isACar($vehicle){
echo 'im a car, model: '.$vehicle.'<br />';
}
//i know this has no sense, in this example at least.
public function printKind(){
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//then?
}
}
$maserati = new plzComplicateMyLife('maserati4', 'car');
//then, maybe, outside the class i'll need to recover the callback:
$maserati->printKind();
EDIT:
As Rob said, polymorphism would be really a good solution.
But the problem is that, in this case, i really must have the same declaration for every class instance, changing only the parameters...e.g:
$maserati = new plzComplicateMyLife('maserati4', 'car');
$ducati = new plzComplicateMyLife('maserati4', 'cycle');
//is good
//becose i cant have:
$maserati = new plzComplicateMyLifeWithACar('maserati4');
$ducati = new plzComplicateMyLifeWithACycle('maserati4');
Polymorphism is the way to go here but for future reference you can also do this:
public function printKind() {
$this->{$this->dynamicFunction}($this->vehicle);
}
In response to your edit, could you not do something like this instead?
abstract class MethodOfTransport {
protected $model;
public function __construct($model) {
$this->model = $model;
}
abstract public function printKind();
public static function create($model, $type) {
$object = new $type($model);
return $object;
}
}
class cycle extends MethodOfTransport {
public function printKind() {
echo 'im a cycle, model: '.$this->model.'<br />';
}
}
class car extends MethodOfTransport {
public function printKind() {
echo 'im a car, model: '.$this->model.'<br />';
}
}
$maserati = MethodOfTransport::create('maserati4', 'car');
$maserati->printKind();
$ducati = MethodOfTransport::create('maserati4', 'cycle');
$ducati->printKind();
In PHP you can use specify a method callback using an array as a callback variable (see here), for example:
array( $object, $methodName );
So you could do this
$callback = array($this, $this->dynamicFunction);
call_user_func($callback, $this->vehicle);
Er, why don't you want to use a simple inheritance structure here? If you want different behaviour depending upon the object modelled, then that's pretty much the canonical description of polymorphism.
If you really do want to plough on with callbacks into the same object, then you'll need to do one of two things:
Drop the $vehicle parameter from your callbacks, make them private or protected, and call into them normally, i.e.
call_user_func( array( $this, 'isACycle' ) );
Mark the callback as static, make them private or protected, and call into them as follows:
call_user_func( array( __CLASS__, 'isACycle' ), $this );
Within the non-static callback, access the object's properties via $this in the normal fashion. Note also that I suggest marking the callback as private or protected, in order to prevent unnecessary outside callers; presumably, you don't want them executing the wrong method for each type.