If, for example, I have a class called images in which I query the database to get a image src, image name, and some other strings:
$sql = Nemesis::select("profile_picture_thumb, profile_picture_large, facebook_id", "users", "id = '{$_SESSION[user_id]}'");
list($profile_picture_thumb, $profile_picture_large, $facebook_id) = $sql->fetch_row();
Is there a way where I can, maybe in __construct set these as a $var in which I can access them in numerous functions within the class? Furthermore, are there any performance benefits in doing this aside from conciseness? I would assume since your essentially querying the database once rather than under numerous function and setting it as a "global" within the class performance would increase... or no?
More explicit:
class Images
{
var $main_prepend = 'm_';
var $thumb_prepend = 't_';
var $default_ext = 'jpg';
var $cropfactor;
private $profile_picture_thumb;
private $profile_picture_large;
private $facebook_id;
public function __construct()
{
$sql = Nemesis::select("profile_picture_thumb, profile_picture_large, facebook_id", "users", "id = '{$_SESSION[user_id]}'");
list($profile_picture_thumb, $profile_picture_large, $facebook_id) = $sql->fetch_row();
$this->profile_picture_thumb = $profile_picture_thumb;
$this->profile_picture_large = $profile_picture_large;
$this->facebook_id = $facebook_id;
}
public function profilePic($show = true, $delete = false)
{
if ($show) {
echo '<script type="text/javascript">$(function() { $("#profile-picture").tipsy({fade: true}); });</script>';
if (is_file(ROOT . $this->profile_picture_thumb)) {
echo '<img src="' . reduce_double_slashes('../' . $this->profile_picture_thumb) . '" id="profile-picture" class="profile-picture" title="Your Profile Picture">';
} elseif (!empty($this->facebook_id)) {
// if there is no profile picture set, and user has listed fb profile picture, get profile picture
$fb_p_thumb = "http://graph.facebook.com/{$facebook_id}/picture";
$fb_p_large = "http://graph.facebook.com/{$facebook_id}/picture?type=large";
echo '<img src="' . $fb_p_thumb . '" id="profile-picture" class="profile-picture" title="Facebook Profile Picture">';
} else {
echo '<img src="images/50x50_placeholder.gif" id="profile-picture" class="profile-picture" title="Click to add profile picture">';
}
}
if ($delete) {
if (is_file(ROOT . $this->profile_picture_thumb) || is_file(ROOT . $this->profile_picture_larg)) {
if (!unlink(ROOT . $this->profile_picture_thumb) && !unlink(ROOT . $this->profile_picture_larg)) {
$msg->add('e', "Could not delete user profile picture!");
}
} else {
$msg->add('e', "Files not found in directory.");
}
}
}
public function profilePicExists($msg = true, $delete = false)
{
if ($msg) {
if (is_file(ROOT . $this->profile_picture_thumb)) {
echo '<div class="ec-messages messages-success">Profile picture exists or was added! It may be required to refresh the page to view changes.</div>';
}
}
if ($delete) {
if (is_file(ROOT . $this->profile_picture_thumb)) {
echo '<input name="doDelete" type="submit" class="btn btn-warning" id="doDelete2" value="Remove Profile Picture">';
}
}
}
Does not work.
class Images {
private $src;
private $name;
public function __construct($src, $name) {
$this->src = $src;
$this->name = $name;
}
public function get_src() {
return $this->src;
}
public function get_name() {
return $this->name;
}
}
$instance = new Images('image.jpg', 'Cute Duck');
echo $instance->get_src();
echo '<br>';
echo $instance->get_name();
Here in your Images class you store the name and the source in two class variables, that you can set in the constructor when you create a new Image class. You can get the values by the two getter function get_name() and get_src().
You could also set these variables to public, sou you could access them directly:
class Images {
public $src;
public $name;
}
$instance = new Images();
$instance->src = 'image.jpg';
$instance->name = 'Cute Duck';
echo $instance->src;
echo '<br>';
echo $instance->name;
You could store and run queries like this:
class Images {
private $query;
private $result;
public function __construct($query) {
$this->query = $query;
//run query than store it in $this->result;
}
public function get_result() {
return $this->result;
}
}
$instance = new Images('SELECT * FROM stuff');
echo $instance->get_result();
This way you can pass the SQL statement in the constructor, where you do your job and store the result. You can access the result through the getter or in any other function that is in the class.
Note that this is not a persistent solution, after you reload the page (or go to another) that use the class in the server side, it starts from the beginning. But you can structure your code and put common functions that you use a lot into the class, so you don't have to duplicate code.
For example you can write an Image class where you can store the name, size, file extension, source, etc. You can give these in the constructor when you create the class or set them via setters or directly if the class variables are public.
After you set these, you can use all of the functions that are in the class. For example you can write a function that copy the image, one that resize or rename it, one that delete it. Any time you need to work with a concrete image you just create a class instance and call the needed functions.
If you want to perform more operations, for example clone an image, than delete the original, or resize the image then clone it, you don't have to set all the settings again for your image because they are stored in the class and the functions have access to it.
Related
i'm writing a php class that is like an orm.
I have a method, that can be called statically or instanciated, and it must work in both cases.
Can you see what's wrong.
Basically is an object called Model.
When created it creates a table based on the inherited class.
For example:
Podcast extends Model ....
There are some functions like this that needs to be called statically and dynamically.
for example:
$podcastList = Podcast::findAll($db);
I get all podcasts objects from DB without need to have a podcast object instanciated.
But i can also do:
$podcast = new Podcast($db)
$podcastList = $podcast->findAll(); //no db here.... passed before
$db is a class i wrote to make operation on Database. IT simply does with OOP, what mysql_* do with functions. I'm not using PDO, i may use in future, but now i use mysql_* :P
that are the incriminated functions
public static function findAll($db=NULL, $self=NULL) {
if($self == NULL) {
$self = new static($db);
} else {
$self = $this;
}
$self->tableName = "";
$self->db = NULL;
$is_static = !(isset($this) && get_class($this) == __CLASS__);
if($is_static) {
//die(__CLASS__ . "::" . __FUNCTION__ . " CALLED STATICALLY");
if(!$self->db) {
die(__CLASS__ . "::" . __FUNCTION__ . " CALLED STATICALLY AND DB IS NULL");
//It stops here!
}
$self->tableName = $self->genTableName();
} else {
$self->db = $this->db;
$self->tableName = $this->tableName;
}
$query = "SELECT * FROM {$self->tableName}";
$r = $self->db->exec($query);
if(!$r) {
die(__CLASS__ . ":Error " . __FUNCTION__ . " record: " . $self->db->getError());
}
if($self->db->countRows($r) == 0) {
return NULL;
}
$objects = array();
while($row = $self->db->fetch($r, DBF::FETCH_ASSOC)) {
$objectClass = __CLASS__;
$object = new $objectClass($this->db);
//TODO Do it dinamically indipendently of column name
$f = get_class_vars($objectClass);
foreach ($f as $field => $value) {
$chuncks = explode("_", $field);
if($chuncks[0] == "f") {
$object->{$field} = $row[$chuncks[2]];
}
}
$objects[] = $object;
}
return $objects;
}
public function __call($name, $arguments) {
if ($name === 'findAll'){
return static::findAll($arguments, $this);
}
}
Both are part of a class.
Thank you for the help !
There's a lot wrong with this code. More important than your many logic mistakes (why are you setting $self = $this, then $self->db = NULL, then $self->db = $this->db?) is that you are misunderstanding what it means to be able to call static functions dynamically in PHP. The object $this simply doesn't exist in a static method. The call $podcast->findAll() looks non-static, but it's still static.
To do what you want to do, here are some options:
leave the function static and call findAll($this->db, $tablename) as needed
put the function into the db class and call it with parameter tablename
EDIT:
The second in my list is how I would do it. This is because you already have to have a db object in your original example, and there is nothing in particular that makes the function's purpose only suited to Podcast objects and not to, say, any other object representing database rows.
//calling examples:
$podcastlist = $db->findAll('Podcast');
$podcast = new Podcast($db);
$podcastlist = $podcast->findAll();
public class db {
....
function findAll($classname, $tablename=NULL) {
if(!isset($tablename)) {
//let's pretend you put default table names as class constants
$tablename = get_constant($classname.'::DEFAULT_TABLE');
}
$query = "SELECT * FROM {$tableName}";
$r = $this->exec($query);
if(!$r) {
throw new Exception("Error " . __FUNCTION__ . " record: " . $this->getError());
}
if($this->countRows($r) == 0) {
return NULL;
}
$objects = array();
while($row = $this->fetch($r, DBF::FETCH_ASSOC)) {
$object = new $classname($this);
//the following is an easier way to do your original foreach
foreach($row as $field=>$value) {
if(property_exists($classname, "f_".$field)) {
$object->{'f_'.$field} = $value;
}
}
$objects[] = $object;
}
//something you forgot:
return $objects;
}
}
public class Podcast extends Model {
....
public function findAll($tablename=NULL) {
return $this->db->findAll(class_name($this), $tablename);
}
}
How can i pass a class as a parameter in my function
So far i've tried
$sc = new SampleClass();
SampleFunction($sc);
function SampleFunction(&$refClass)
{
echo $refClass->getValue();
}
this is a simplified example of what im doing.. i actually have to do complex procedures inside this sample function. I'm not getting any response from the sample function. What am i doing wrong? thank you
UPDATE
char.php
class Charss {
var $name=0;
var $hp=500;
var $spd=10;
var $rtime=10;
var $dmg=10;
function __construct( $name, $hp, $spd, $rtime , $dmg) {
$this->name = $name;
$this->hp = $hp;
$this->spd = $spd;
$this->rtime = $rtime;
$this->dmg = $dmg;
}
function get_name() {
return $this->name;
}
function set_name($new_name) {
$this->name = $new_name;
}
function get_hp() {
return $this->hp;
}
function set_hp($new_hp) {
$this->hp = $new_hp;
}
function get_spd() {
return $this->spd;
}
function set_spd($new_spd) {
$this->spd = $new_spd;
}
function get_rtime() {
return $this->rtime;
}
function set_rtime($new_rtime) {
$this->rtime = $new_rtime;
}
function get_dmg() {
return $this->get_dmg;
}
function set_dmg($new_dmg) {
$this->dmg = $new_dmg;
}
}
myclass.php
require("char.php");
class Person {
function try_process()
{
$chr1 = new Charss("Player1",500,3,0,50);
$chr2 = new Charss("Player2",500,6,0,70);
while ($chr1->get_hp() > 0 && $chr2->get_hp() > 0)
{
$sth = min($chr1->get_rtime(), $chr2->get_rtime());
if ($chr1->get_rtime() == 0 && $chr2->get_rtime() > 0)
{
exit;
Fight($chr1,$chr2);
$chr1->set_rtime($chr1->get_spd());
}
elseif ($chr2->get_rtime() == 0 && $chr1->get_rtime() > 0)
{
Fight($chr2,$chr1);
$chr2->set_rtime($chr2->get_spd());
}
else
{
Fight($chr1,$chr2); #having trouble with this
$chr1->set_rtime($chr1->get_spd());
}
$chr1->set_rtime($chr1->get_rtime() - $sth);
$chr2->set_rtime($chr2->get_rtime() - $sth);
}
}
function Fight($atk,$def)
{
$def->set_hp($def->get_hp() - $atk->get_dmg());
echo $atk->get_name() . " attacked " . $def->get_name() . " for " . $atk->get_dmg() . " damage";
}
}
so im calling the function try_process on button click
What you're actually doing there is passing an object, not a class.
$sc = new SampleClass();
creates an instance of SampleClass, aka an object.
I assume there's some error being thrown elsewhere as what you have is correct.
I tested the following code and got the expected output:
class SampleClass
{
public function getValue()
{
return 4;
}
}
$sc = new SampleClass();
SampleFunction($sc);
function SampleFunction(&$refClass)
{
echo $refClass->getValue();
}
Output: 4
If you provide more details of your actual code we might be able to determine the problem.
I can't see anything wrong with your code
using &$refClass is however is not recommended and I guess willbe removed from future iteration of PHP version
but here is an example
class objects are passed as reference I suppose so no need of '&'
http://ideone.com/GbmUy
Why is the function argument a reference? Probably shouldn't be.
Other than that, there's nothing wrong with you posted, so the error is likely within SampleClass.
Others have answered pretty well, but this is a silly little example to show you how to modify the class (either by calling a property setter, or setting public properties directly)
class foo {
private $member1;
public $member2;
public function __construct($member1,$member2) {
$this->member1=$member1;
$this->member2=$member2;
}
public function SetMember1($value) {
$this->member1 = $value;
}
public function GetMember1() {
return $this->member1;
}
}
function SetMembers(foo $obj, $member1, $member2) {
// Call a setter
$obj->SetMember1($member1);
// Set a member variable directly
$obj->member2 = $member2;
}
$obj = new foo('default member 1', 'default member 2');
echo "member1 (before): {$obj->GetMember1()}\n";
echo "member2 (before): {$obj->member2}\n";
// Change values
SetMembers($obj, 'new member1', 'new member2');
echo "member1 (after): {$obj->GetMember1()}\n";
echo "member2 (after): {$obj->member2}\n";
This will output:
member1 (before): default member 1
member2 (before): default member 2
member1 (after): new member1
member2 (after): new member2
I have the following situation.
I have a class with a lot of functions. Each function starts with executing the same method. Is there a way that I can like implement this method into the function so that it is executed automatically?
Here is an example:
class test
{
static function_1($param) {some_method($param); other stuff....}
static function_2($param) {some_method($param); other stuff then function 1....}
static function_3($param) {some_method($param); other stuff then function 1 and function 2....}
}
So is there a way to execute some_method(); automaticly without declaring it in each function?
Thanks in advance!
Whole code:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
* The Assets Library
*
* This class let's you add assets (javascripts, stylesheets and images) way easier..
*/
class Assets {
private $css_url;
private $js_url;
private $img_url;
public function __construct()
{
$CI =& get_instance();
$CI->config->load('assets');
$asset_url = base_url() . $CI->config->item('assets_dir');
$this->css_url = $asset_url . $CI->config->item('css_dir_name');
$this->js_url = $asset_url . $CI->config->item('js_dir_name');
$this->img_url = $asset_url . $CI->config->item('img_dir_name');
}
// Returns the css html link
public function css_html_link($filename)
{
// Check whether or not a filetype was given
$filename = $this->_add_filetype($filename, 'css');
$link = '<link type="text/css" rel="stylesheet" href="' . $this->css_url . $filename . '" />';
return $link;
}
// Returns the css link
public function css_link($filename)
{
$filename = $this->_add_filetype($filename, 'css');
return $this->css_url . $filename;
}
// Returns the js html link
public function js_html_link($filename)
{
$filename = $this->_add_filetype($filename, 'js');
$script = '<script type="text/javascript" src="' . $this->js_url . $filename . '"></script>';
return $script;
}
// Return the js link
public function js_link($filename)
{
$filename = $this->_add_filetype($filename, 'js');
return $this->js_url . $filename;
}
// Returns the image html tag
public function img_html_link($filename, $rel = NULL)
{
// Get the filename without the filetype
$alt_text = substr($filename, 0, strpos($filename, '.')+1);
$alt_text = 'alt="'.$alt_text.'"';
// If relation is giving, use it
$img_rel = ($rel !== FALSE) ? 'rel="' . $rel . '"' : '';
$image = '<img src="' . $this->img_url . $filename . '" '.$rel.' ' . $alt_text . '/>';
return $image;
}
// Return the image link
public function img_link($filename)
{
return $this->img_url . $filename;
}
// Check whether or not a filetype was specified in $file, if not, it will be added
private function _add_filetype($file, $type)
{
if(strpos($file, '.' . $type) === FALSE)
{
$file = $file . '.' . $type;
}
return $file;
}
}
/* End of file assets.php */
/* Location: ./application/libraries/assets.php */
every time you initiate the class, it calls the __construct() function, or in PHP 4 (I hope you are not using php 4) it uses the function with the same name as the class
If you do this, it should work for every initiate of the class:
function __construct($param){
some_method($param);
}
if you call multiple functions in the same initiation of the class, you could do this:
var $param;
function __construct($param){
$this->param = $param;
}
function doMethod(){
some_method($this->param);
}
function function_1()
{
$this->doMethod();
}
Calling the class multiple times, with different params. Perhaps try this approach:
function __call($function, $param){
some_method($param);
switch ($function){
case 'function1':
$this->function1($param);
break;
/// etc..
}
}
I'm afraid that in this case the answer is 'no'.
You're not 'declaring' some_method() each time, you are calling it. If you don't call it, it can't run, so you have to call it each time.
Cut & paste.....
Why not paste your actual code here, some refactoring may help.
Edit after seeing actual code
I can't see the problem with your existing code. It is clear and you will know what it does in a year's time. I would keep it as it is. The answer you accepted will work, but it is obfuscating your code. You will have problems working out what you did and why you did it in when you come back to maintain your code in the future.
You could create a class containing an instance of the class test (composition) and implement its __call magic method. Something akin to:
class testWrapper
{
private $test;
function __construct()
{
$this->test = new Test();
}
function __call($name, $args)
{
call_user_func_array(array($this->test, 'some_method'), $args);
call_user_func_array(array($this->test, $name), $args);
}
}
You then call methods from the test class on the instance object of testWrapper.
You can further refine the logic in the __call method to only call some_method() based on the passed-in method name, etc.
I've looked at similar questions like this, and none of the solutions offered within them seems to answer my question.
This is the code I have so far (just learning OOP):
<?php
class page {
var $ot;
function begin(){
$this->ot = '';
}
function finish(){
echo $this->ot;
}
class forms extends page {
function __construct($form_action, $form_type){
$this->ot .= '<form action=' . $form_action . ' method=' . $form_type . ' />';
}
function create_input($type, $name){
$this->ot .= '<input type="' . $type . '" name="' . $name . '" /><br />';
}
function create_submit($value){
$this->ot .= '<input type="submit" value="' . $value . '" />';
}
function __destruct(){
$this->ot .= '</form>';
}
}
class labels extends page {
function create_label($label){
$this->ot .= '<label>' . $label . ' </label>';
}
}
$page = new page();
$page->begin();
$newform = new forms('/class_lib.php', 'GET');
$newlabels = new labels();
$newlabels->create_label('Username:');
$newform->create_input('text', 'username');
$newlabels->create_label('Password:');
$newform->create_input('password', 'password');
$page->finish();
?>
For some reason, this code does not output anything to the browser. However, if I change the child classes forms and labels to echo their output instead of storing it in the parent variable the code seems to spring to life and works as intended.
Excuse my ignorance as I am new to OOP.
Thanks!
$ot is an object-property. This means, that every object of the class page or any subclass has its own "version" of $ot. Now you instanciate some objects and set some values, but at the end, when you call $page->finish(); $page->ot is empty anyway.
In OOP you have the classes (types) and instances of the classes (objects). The $ot property is what you call an instance variable, it belongs to the instances (objects) you create and is not a property of the class itself.
By making forms a subclass of page, you get what you call a "is a" relationship between the classes. That means that forms will inherit the structure of the page class. Modifying the property of a subclass object will not affect the superclass objects or any other object in this case.
When you first create a page object, that object has a $ot property. When you create a object of type forms, that object has its own $ot property.
To understand the concepts of OOP I would recommend you to read some tutorials. You could start by reading the Class, Instance and Inheritance parts of this wikipedia article:
http://en.wikipedia.org/wiki/Object-oriented_programming
The objects are not really connected.
You create three new objects, but they never reference each other.
Try this
// Create a new form
$newform = new forms('/class_lib.php', 'GET');
$newform->create_input('text', 'username');
$newform->create_input('password', 'password');
// Output the form, it can use the finish() method because it extends page
$newform->finish();
This will work and output the <input> elements, but your label class isn't plugged in to the $newForm to do anything, its just created and is completely separate.
EDIT - bored this evening....
You will need PHP5 to run this, its not perfect, but its a good start! I have defined the following an interface called renderable and classes called element, input, label and form
// An interface describes the methods that a class must use
interface renderable
{
// Any classes that implement the renderabe interface must define a method called render()
function render();
}
// This abstract class can never be created, so you can never do new element(), it implements renderable
abstract class element implements renderable
{
// Set up some variables for all elemnts
var $attribs = array();
var $name = "";
var $type = "";
// The construct for a element needs a type and a name
function __construct($type, $name)
{
$this->name = $name;
$this->type = $type;
}
// Set an attribute for the element
function setAttribute($name, $value)
{
$this->attribs[$name] = $value;
}
// Get the name of this element
function getName()
{
return $this->name;
}
// The render function outputs an element
function render()
{
// Output the start of the element eg <input
echo "<" . $this->type . " ";
// each attribute eg class='blue'
foreach($this->attribs as $name => $value)
echo " " . $name . "='" . $value ."' ";
// end the element
echo " />";
echo "<br />";
}
}
// The input element extends element but is not abstract
class input extends element
{
// Nothing is overridden here from the parent class element
}
// The label element extends element but is not abstract
class label extends element
{
// Define a new var called label, this is special for the label element
var $label = "";
// Override the contruct for element to only accept a name, this
// is because the label element type will always be label
function __construct($name)
{
$this->name = $name;
$this->type = "label";
}
// Set the label var
function setLabel($label)
{
$this->label = $label;
}
// Override the render function, this means that label has its own render function
// and does not use the function from the abstract class element
function render()
{
echo "<" . $this->type . " ";
foreach($this->attribs as $name => $value)
echo " " . $name . "='" . $value ."' ";
echo " >";
// Here the special label content is displayed
echo $this->label;
echo "</label>";
}
}
// A form extends element
class form extends element
{
// A form has some new vars
var $elements = array();
var $labels = array();
var $action;
var $method;
// Override the contruct and use name, action and method
// There are default values for action and method so they are not required
function __construct($name, $action = "/", $method = "GET")
{
$this->name = $name;
$this->type = "form";
$this->action = $action;
$this->method = $method;
}
// Add a new element to the form along with its label
function appendElement($element, $label)
{
// Add these to an array inside this class
$this->elements[$element->getName()] = $element;
$this->labels[$label->getName()] = $label;
}
// Override the render function
function render()
{
// Output the form's start along with the method and action
echo '<' . $this->type. ' ' . 'action="' . $this->action . '" method="' . $this->method . '" />';
// Iterate over the array of elments and render each one
foreach($this->elements as $name => $ele)
{
// Render the label for the current element
$this->labels[$name]->render();
// Render the element
$ele->render();
}
// End the form
echo "</form>";
}
}
// Create form with name, action and method
$form = new form("login", "/login.php", "POST");
// Create input username
$ele = new input("input", "username");
// Set type
$ele->setAttribute("type", "text");
// Set a class
$ele->setAttribute("class", "blue");
// Create a label for the username long with its content
$label = new label("username");
$label->setLabel("Username: ");
// Add the username element and its label
$form->appendElement($ele, $label);
// Repeat for password
$ele = new input("input", "password");
$ele->setAttribute("type", "password");
$label = new label("password");
$label->setLabel("Password: ");
$form->appendElement($ele, $label);
// Render the form
$form->render();
Since you're learning OOP, it's time to learn about Abstract Classes (PHP Manual)!
An abstract class is a sort of skeleton class that defines a series of generic functions. An abstract class can never be instantiated (i.e., you cannot call new AbstractClass), but can be extended by other classes. This allows us to define something generic and repeatable, say, and HTML Element, and then extend that to specific HTML elements as time goes on. Here is a sample implementation of that concept.
WARNING: I am not saying that this implementation is a great idea; learning purposes only!
First, some abstract classes to define how this stuff ought to work.
abstract class HTMLWriter
{
protected $html = '';
protected $tagName = null;
protected $selfClosing = false;
protected $elements = array();
protected $attributes = array();
protected $closed = false;
abstract public function __construct();
public function addElement(HTMLWriter $element)
{
if ($this->closed || $this->selfClosing) {
return;
}
$element->close(); // automatic!
$this->elements[] = $element->write();
}
public function addElements() {
foreach (func_get_args() as $arg) {
if ($arg instanceof HTMLWriter) {
$this->addElement($arg);
}
}
}
public function addAttribute($name, $value)
{
return $this->attributes[$name] = $value;
}
public function write()
{
if (!$this->closed) {
$this->close();
}
return $this->html;
}
public function close()
{
$this->closed = true;
$this->html = '<' . $this->tagName;
foreach ($this->attributes AS $attr => $val) {
$this->html .= ' ' . $attr . '="' . $val . '"';
}
if ($this->selfClosing) {
$this->html .= '/>';
return;
}
$this->html .= '>';
foreach($this->elements as $elem) {
$this->html .= $elem;
}
$this->html .= '</' . $this->tagName . '>';
}
}
abstract class HTMLWriterWithTextNodes extends HTMLWriter
{
//abstract public function __construct();
public function addText($text)
{
$this->elements[] = htmlentities($text);
}
public function addTextRaw($text)
{
$this->elements[] = $text;
}
}
And then the concrete implementations of those classes:
note: a concrete class is any non-abstract class, although this term loses its meaning when applied to classes that are not extensions of abstract classes.
class Form extends HTMLWriter
{
public function __construct($action, $method, $can_upload = false)
{
$this->tagName = 'form';
$this->addAttribute('action', $action);
$this->addAttribute('method', $method);
if ($can_upload) {
$this->addAttribte('enctype','multipart/form-data');
}
}
}
class Input extends HTMLWriter
{
public function __construct($type, $name, $id = null)
{
$this->tagName = 'input';
$this->selfClosing = true;
$this->addAttribute('type', $type);
$this->addAttribute('name', $name);
if (!is_null($id)) {
$this->addAttribute('id', $id);
}
}
// overrides
public function addElement()
{
return false;
}
}
class Label extends HTMLWriterWithTextNodes
{
public function __construct($labelText = null, $for = null)
{
$this->tagName = 'label';
if (!is_null($labelText)) {
$this->elements[] = $labelText;
}
if (!is_null($for)) {
$this->addAttribute('for', $for);
}
}
}
class GenericElement extends HTMLWriterWithTextNodes
{
public function __construct($tagName, $selfClosing = false)
{
if (empty($tagName)) {
$this->closed = true;
$this->html = '';
return;
}
$this->tagName = $tagName;
$this->selfClosing = (bool)$selfClosing;
}
}
Finally, let's instantiate and use our new classes
$form = new Form('/class_lib.php','get');
$username = new Input('text','username','username');
$password = new Input('password','password','password');
$submit = new Input('submit','login');
$submit->addAttribute('value','login');
$ulabel = new Label('Username: ', 'username');
$plabel = new Label('Password: ','password');
$br = new GenericElement('br',true);
$form->addElements(
$ulabel, $username, $br,
$plabel, $password, $br,
$submit
);
echo $form->write();
Output:
<form action="/class_lib.php" method="get"><label for="username">Username: </label><input type="text" name="username" id="username"/><br/><label for="password">Password: </label><input type="password" name="password" id="password"/><br/><input type="submit" name="login" value="login"/></form>
Hooray for abstract classes!
I'm very new to PHP and OOP in general. I'm using codeigniter for a framework, and am currently attempting to build a class 'BuildLinks' that will redirect the user to the correct link based on what URL they landed on.
The controller passes the right variables to the class, while the function build_afflink() selects what class to call next based on the var1
The controller:
function out($var1, $var2)
{
// redirect to link after parsing data
$debug='1';
$params = array('var1'=>$var1, 'var2'=>$var2);
$this->load->library('BuildLinks', $params);
if ($debug=='0'){
$redirect = $this->buildlinks->build_afflink();
redirect($redirect, 'location', 301);
}
else {
var_dump($this->buildlinks->build_afflink());
}
}
The class BuildLinks is a work in progress... but it is extended by all of the other sites I need to support.
BuildLinks class:
class BuildLinks
{
public $var1;
public $var2;
public $link;
function __construct($params)
{
//populate up inititial variables from $params array (passed from controller)
$this->var1 = (string)$params['var1'];
$this->var2 = (string)$params['var2'];
echo __class__ . ' loaded....' . 'var1: '.$this->var1 . ' var2: ' .$this->var2. '<br/>';
}
public function get_var1()
{
return $this->var1;
}
public function set_var1($var1)
{
$this->var1 = $var1;
}
public function get_var2()
{
return $this->var2;
}
public function set_var2($var2)
{
$this->var2 = $var2;
}
function build_thelink()
{
switch ($this->var1) {
case 'amazon':
//echo 'Amazon is our vendor.<br>';
$newobj = new Amazon;
// Amazon subclass returns the correct affiliate link
return $newobj->affiliate_link();
break;
case 'ebay':
$newobj = new Ebay;
//ebay subclass however, cannot access the public var var1, it returns a null value for $this->var1
return $newobj->affiliate_link();
break;
}
}
}
Essentially, when I make a new Ebay object, it can't access any of the public variables from the parent class BuildLinks. What am I doing wrong?
In this example, I have it construct the initial variables and echo back out some information for debugging.
EDIT: If I change the __construct to read:
function __construct($params)
{
//populate up inititial variables from $params array (passed from controller)
$this->var1 = (string)$params['var1'];
$this->var2 = (string)$params['var2'];
echo __class__ . ' loaded....' . 'var1: '.$this->var1. ' var2: ' .$this->var2 . '<br/>';
var_dump(get_class_vars(get_class($this)));
}
Then I get this as an output:
BuildLinks loaded....var1: ebay var2: somedata
array
'var1' => null
'var2' => null
'link' => null
The following works fine:
$newobj = new Amazon;
return $newobj->affiliate_link();
This does not, but the classes are almost identical...
$newobj = new Ebay;
return $newobj->affiliate_link();
Here is the ebay class:
class Ebay extends BuildLinks
{
private $res;
//TODO: language/multiple site support
//public $locale;
function __construct()
{
//echo __class__ . ' loaded....' . 'vendor: '.$this->vendor . ' isbn: ' .$this->isbn . '<br/>';
}
function add_to_cart_button($isbn, $locale)
{
}
function affiliate_link()
{
$this->get_info();
return $this->link;
}
// Load $this->api_call() and return Amazon SimpleXML response object, load variables
function get_info()
{
$apicall = $this->api_call();
//build variables
foreach ($apicall->searchResult->item as $item) {
$this->link = (string )$item->viewItemURL;
}
}
// Generate API call and return simplexml object $res
function api_call()
{
//build $apicall here
$res = simplexml_load_file($apicall);
// Check to see if the request was successful, else print an error
if ($res->ack == "Success") {
$this->res = $res;
return $res;
} else {
echo 'api_call() unsuccessful';
}
}
}
This part of the ebay class doesn't make too much sense to me:
function api_call()
{
//build $apicall here
$res = simplexml_load_file($apicall);
// Check to see if the request was successful, else print an error
if ($res->ack == "Success") {
$this->res = $res;
return $res;
} else {
echo 'api_call() unsuccessful';
}
}
simplexml_load_file($apicall); specifically isn't loading anything. Where's $apicall? If you debug that, does it echo "api_call() unsuccessful"?
Because if that's unsuccessful then Ebay::link won't be set and as a result return $newobj->affiliate_link(); wouldn't end up returning anything.
for clarification, $apicall should be set to a file path before calling simplexml_load_file($apicall);
Ebay::get_info() does this
foreach ($apicall->searchResult->item as $item) {
$this->link = (string )$item->viewItemURL;
}
If $apicall->searchResult->item happens to have several elements, last of which is empty, you'll get only that last empty element.
That's a wild guess though.
[added]
You're overwriting a constructor in Ebay, so if you want BuildLinks' class constructor to be called, you need to do this explicitly.