I have a master class and semi-master class. Master class core is a class that prints all head, nav, footer and meta elements. Class Base prints content related data and all page-level classes extend it and print their data within specific div.
My problem is that functions and globals are not within scope in one of functions within Base class. Where did I go wrong?
abstract class Core {
abstract protected function print_content();
}
abstract class Base extends Core {
abstract protected function print_page_content();
public function print_content(){
ob_start();
$this->get_nav();
$output = ob_get_contents();
$output .= ' ... '.$this->print_page_content().' ...';
ob_end_clean();
}
}
class Page extends Base {
private function get_games(){...}
private function process_form(){...}
public function print_page_content(){
$this->process_form(); # <--- function doesn't see it (!)
$output = '..... '.$this->get_games().' .... '; # <-- function DOES see this tho (!)
$GLOBALS['m_id']; # <-- or any other global such as $_GET, $_POST is not under scope.
return $output;
}
When I do error reporting it doesn't print any error. It just ignores line where function was called.
However, When I would force error, error would appear.
Let's focus on the technical aspect (and not smaller glitches or design decisions).
I don't think the code snippet you've posted "contains" the error. Let me give you a version that contains everything you've shown us and only adds things that do not "collide" with your code snippet, i.e. minimal implementations of what you've left out (again: purely technical).
<?php
abstract class Core {
abstract protected function print_content();
}
abstract class Base extends Core {
abstract protected function print_page_content();
public function print_content(){
ob_start();
$this->get_nav();
$output = ob_get_contents();
$output .= '###'.$this->print_page_content().'###';
ob_end_clean();
echo $output;
}
public function get_nav() {
echo '| Base::get_nav |';
}
}
class Page extends Base {
protected $names = array();
private function get_games(){ return htmlspecialchars(var_export($this->names, true)); }
private function process_form(){ $this->names['Jean']="D'Arc"; $this->names['John']='Malkovich';}
public function print_page_content(){
$this->process_form();
$output = '<pre>'.$this->get_games().'</pre>';
$output .= '<p>'.$GLOBALS['m_id'].'</p>';
return $output;
}
}
$m_id = 4711;
$p = new Page;
$p->print_content();
it prints
| Base::get_nav |###<pre>array (
'Jean' => 'D\'Arc',
'John' => 'Malkovich',
)</pre><p>4711</p>###
( check here: https://3v4l.org/ZBQ0b )
as it is supposed to do.
So, where does your script differ from this script? Try to minimize your script for testing purposes in order to find the cause.
edit: suggested improvement(s) for your sscce
private function process_form(){
// $stmt = add your prepare()/statement here as a comment
$params = array(/* put in all the variables here, you would bind*/);
// <-- maybe the actual bind code here as comment -->
return var_export( $params, true );
}#endfunc(process_form)
public function print_page_content(){
$pf = $this->process_form();
$output = 'print_page_content stuff...'.$this->get_games()
.' <pre>'.$pf.'</pre>';
return $output;
}#endfunc(print_page_content)
After the abstract class is inherited, the abstract method cannot be rewritten.
Related
class KD_DB extends PDO {
protected static $dbOne = '';
protected static $dbTwo = '';
public function setVariable ($alias,$content){
switch($alias){
case'one': self::$dbOne = $content; break;
case'two': self::$dbTwo = $content; break;
}
}
}
Is there a way to create these dynamically?
Something like this to create the protected static variables
public function setVariable ($alias,$content){
self::${$alias} = $content;
}
It did not work, but I suspect it is because I need it to be static to make it to work with a third class that extends this one...
If you only have the two variables, it may be easier (with more appropriate names) to set them using a static function for each one, something like...
class KD_DB {
public static $dbOne = '';
public static $dbTwo = '';
public static function setOne ($content){
self::$dbOne = $content;
}
}
KD_DB::setOne("value for one");
var_dump(KD_DB::$dbOne);
(code with minor changes to show the process)
But if you wanted a more open ended method, I would go for an associative array as the static variables and then use the 1 method (like you currently are) to set the value in the array...
class KD_DB {
public static $data = [];
public static function setVariable ($alias,$content){
self::$data[$alias] = $content;
}
}
KD_DB::setVariable("three", "value for three");
var_dump(KD_DB::$data);
this method can have issues if you mistype a variable reference which should be found during testing though, but does offer flexibility.
I've been trying for a long time now to find a correct design using PHP to achieve what I want, but everything I've tried failed and I'm guessing it's probably because I'm not looking from the right angle, so I wish some of you can enlighten me and give me some good advice!
The design might seem a little weird at first, but I assure you it's not because I like to make things complicated. For the sake of simplicity I'm only giving the minimal structure of my problem and not the actual code. It starts with these:
<?php
// ------------------------------------------------------------------------
class Mother_A
{
const _override_1 = 'default';
protected static $_override_2 = array();
public static function method_a()
{
$c = get_called_class();
// Uses $c::_override_1 and $c::$_override_2
}
}
// ------------------------------------------------------------------------
class Mother_B extends Mother_A
{
public function method_b()
{
// Uses self::method_a()
}
}
Class Mother_A defines a static method that uses constants and statics to be overridden by children. This allows to define a generic method (equivalent of a "template" method) in the derived class Mother_B. Neither Mother_A or Mother_B are intended to be instanciated, but Mother_B should not be abstract. This exploits Late Static Binding, which I find very useful btw.
Now comes my problem. I want to define two classes, in n distinct 'situations' (situation 1, situation 2, etc):
<?php
// ------------------------------------------------------------------------
class Child_A_Situation_k extends Mother_A
{
// Uses method_a
}
// ------------------------------------------------------------------------
class Child_B_Situation_k extends Mother_B
{
// Uses method_a and method_b
}
Of course I'm not actually giving these stupid names; both classes have different names in each situation, but both follow the same derivation pattern from Mother_A and Mother_B. However, in each individual case ('situation'), both classes need the exact same constants/static override, and I don't know how to do that without duplicating the override manually in both classes.
I tried many things, but the closest I got was to implement an interface Interface_Situation_k that defined constants and statics for the situation k, and make both children implement this interface. Of course, you can't define statics in an interface, so it failed, but you get the idea. I would have traded the interface for a class, but then there's no multiple inheritance in PHP, so it's not valid either. :/ I'm really stuck, and I can't wait to read a possible solution! Thanks in advance!
this is the best i can do, i don't think there is a way to do it with less code.
Look at the comments inside the code for more info.
Fully working code:
<?php
class Mother_A
{
// you're using '_override_1' as a variable, so its obviously not a constant
// also i made it public for the setSituation function,
// you could keep it protected and use reflections to set it
// but i dont really see a reason for that.
// if you want that, look up how to set private/protected variables
public static $_override_1 = 'default';
public static $_override_2 = array();
public static function method_a()
{
$c = get_called_class();
var_dump($c::$_override_1);
var_dump($c::$_override_2);
// Uses $c::_override_1 and $c::$_override_2
}
public static function setSituation($className)
{
$c = get_called_class();
// iterate through the static properties of $className and $c
// and when the you find properties with the same name, set them
$rBase = new ReflectionClass($c);
$rSituation = new ReflectionClass($className);
$staBase = $rBase->getStaticProperties();
$staSituation = $rSituation->getStaticProperties();
foreach($staSituation as $name => $value)
{
if(isset($staBase[$name])) $c::$$name = $value;
}
}
}
// ------------------------------------------------------------------------
class Mother_B extends Mother_A
{
public function method_b()
{
self::method_a();
}
}
class Situation_k
{
public static $_override_1 = 'k';
public static $_override_2 = array('k','k');
}
class Child_A_Situation_k extends Mother_A { }
Child_A_Situation_k::setSituation('Situation_k');
// This is not as short as writing 'extends Mother_A, Situation_k'
// but i think you wont get it shorter
class Child_B_Situation_k extends Mother_B { }
Child_B_Situation_k::setSituation('Situation_k');
echo '<pre>';
Child_A_Situation_k::method_a();
echo "\n";
Child_B_Situation_k::method_a();
echo "\n";
Child_B_Situation_k::method_b();
echo "\n";
echo '</pre>';
?>
I'm just experimenting with OOP programming I'm trying to create a form class. I'm unable to print the checkbox, how can I check where things are going wronge?
require_once('form.php');
$gender = new Checkbox('Please select your gender','gender',array('male','female'));
echo $gender->show_checkbox();
File with class:
class Inputfield{
public $id;
public $options_array;
public $question;
public $type;
function __construct($newquestion,$newid,$newoptions_array){
$this->question=$newquestion;
$this->id=$newid;
$this->type="txt";
$this->options_array=$newoptions_array;
}
public function show_options($options_arr,$type,$id,$classes){
$output="";
foreach($options_arr as $option){
$output.="<label for=\"".$option."\"></label><input name=\"".$option."\" type=\"".$type."\" id=\"".$id."\" class=\"".$classes."\">";
}
return $output;
}
public function show_question(){
$output="<h3 class='question'>".$this->vraag."</h3>";
return $output;
}
}
class Checkbox extends Inputfield{
function __construct($newquestion,$newid,$newoptions_array){
$this->question=$newquestion;
$this->id=$newid;
$this->type="checkbox";
$this->options_array=$newoptions_array;
}
public function show_checkbox(){
$output=show_question();
$output.=show_options($this->options_array,'checkbox',$this->id,'class');
return $output;
}
}
You call instance methods with $this: $this->show_options();
You don't need to copy-paste the whole constructor as soon as it's identical to the one in parent class
In case if it matches partially you can call it like parent::__construct(...) and then define a custom $this->type="checkbox";
You can not define it in runtime but specify it as a property default value.
You should use $this in an object context. Eg. in your show_checkbox method, write:
$output = $this->show_question();
$output .= $this->show_options(...);
Supposed there is a function in a \AW\Blog\Model\post.php.there is a function in it.
public function PreNext($type){
$id = $this->_data['post_id'];
$blog = Mage::getResourceModel('blog/post_collection');
$blog->getSelect()->where('post_id>?',$id);
return $blog->getFirstItem();
}
why it write $this->_data['post_id']; could i write it with another.
what are the four lines meaning which in the function within magento.? many thanks.
the post.php
class AW_Blog_Model_Post extends Mage_Core_Model_Abstract{
const NOROUTE_PAGE_ID = 'no-route';
protected function _construct(){
$this->_init('blog/post');
}
public function load($id, $field=null){
return $post = parent::load($id, $field);
}
public function noRoutePage(){
$this->setData($this->load(self::NOROUTE_PAGE_ID, $this->getIdFieldName()));
return $this;
}
public function getShortContent(){
$content = $this->getData('short_content');
if(Mage::getStoreConfig(AW_Blog_Helper_Config::XML_BLOG_PARSE_CMS)){
$processor = Mage::getModel('core/email_template_filter');
$content = $processor->filter($content);
}
return $content;
}
public function getPostContent(){
$content = $this->getData('post_content');
if(Mage::getStoreConfig(AW_Blog_Helper_Config::XML_BLOG_PARSE_CMS)){
$processor = Mage::getModel('core/email_template_filter');
$content = $processor->filter($content);
}
return $content;
}
public function loadByIdentifier($v) {
return $this->load($v, 'identifier');
}
}
This is code of a custom extension, so only people having this extension can know, what this post.php file contains, and whether you can get the value using other ways than $this->_data['post_id'].
If the extension uses standard Magento Getters/Setters, maybe $this->getPostId() may work, too.
The rest loads a collection of records having a post_id greater than $this->_data['post_id'], but returns only the first record found.
Update
The class you posted extends
Mage_Core_Model_Abstract
which in turn extends
Varien_Object
in a standard Magento OOB.
The Varien_Object class defines the standard getters/setters I was talking about, so yes, you can also use $this->getPostId() to get the value.
To understand how these getters/setters work, I'd recommend to check the Varien_Object and read about PHPs magic methods, like __call(), __get() and __set().
I'm trying to decide the design of a system which is meant to allow for a high amount of extensiblity. From what I can tell, a pattern such as the abstract factory would not allow for overriding of the base methods, apart from duplicating code (as demonstrated below).
I've done some preliminary research into aspect oriented programming and it seems to be along the lines of what I'm looking for but I'm having a difficult time wrapping my head around the specifics.
abstract class Object {
protected $object_id;
protected $name;
function LoadObjectData()
{
$file_contents = readfile('object'.$object_id.'.data');
$data = array();
// parse file contents into $data array...
return $data;
}
function Create()
{
$data = $this->LoadObjectData();
$name = $data['name'];
return $data;
}
}
class User extends Object {
protected $email_address;
function Create()
{
$data = parent::Create();
$this->email_address = $data['email_address'];
return $data;
}
}
//----------Module 1-MySQL Lookup-------------
/*
* Redefine Object::LoadObjectData() as follows:
*/
function LoadObjectData()
{
$data = array();
$result = mysql_query("SELECT...");
// construct array from result set
return $data;
}
//----------Module 2-Cache Machine-------------
/*
* Redefine Object::LoadObjectData() as follows:
*/
function LoadObjectData()
{
if (exists_in_cache($object_id)) {
return get_cached_object($object_id);
}
$data = parent::LoadObjectData();
cache_object($object_id, $data);
return $data;
}
(This is sort of a poor example, but hopefully it helps to get my point across)
The intended system would have a very large proportion of methods available to be extended and I would like to minimize the extra effort and learning necessary for developers.
Is AOP exactly what I'm looking for, or is there a better way to deal with this?
Thanks!
So, you want to use a decorator pattern without defining the decorator itself.
If yes, then it's a monkeypatching and can be done with aspect-oriented tools. This can be solved easily with following extensions and frameworks:
PHP Runkit Extension
Go! Aspect-Oriented framework for PHP
PHP-AOP Extension.
You don't have to declare the base class as an abstract class. You can make it a regular class and have it load and instantiate other classes based on passed construct parameters. The constructor can return an instance of a class, not just the class the constructor is in. To avoid duplicating code, you can mix static with instantiated functions and variables. Just remember that a static function or variable is the same for ALL instances. Change a static variable in one and it is changed for all instances. A rather basic example of a plugin architecture.
class BaseObject {
protected static $cache = array();
public function __construct($load_plugin) {
require_once($load_plugin.'.class.php');
$object = new $load_plugin();
return $object;
}
public static function cacheData($cache_key, $data) {
self::$cache[$cache_key] = $data;
}
}
class Plugin extends BaseObject {
public function __construct() {
}
public function loadData() {
// Check the cache first
if ( !isset(self::$cache[$cache_key]) ) {
// Load the data into cache
$data = 'data to cache';
self::cacheData($cache_key, $data);
}
return self::$cache[$cache_key];
}
}