Get Classname of Inherited Class when using Scope Resolution Operator (::) [duplicate] - php

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Functionality of PHP get_class
For a small ORM-ish class-set, I have the following:
class Record {
//Implementation is simplified, details out of scope for this question.
static public function table() {
return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', get_class()))."s";
}
static public function find($conditions) {
//... db-selection calls go here.
var_dump(self::table());
}
}
class Payment extends Record {
}
class Order extends Record {
public $id = 12;
public function payments() {
$this->payments = Payment::find(array('order_id', $this->id, '='));
}
}
$order = new Order();
$order->payments();
#=> string(7) "records"
I would expect this code to print:
#=> string(8) "payments"
But, instead, it prints records. I have tried self::table(), but that gives the same result.
Edit, after some questions in the comments table() is a method that simply maps the name of the Class to the table in wich its objects live: Order lives in orders, Payment lives in payments; records does not exist!). When I call Payments::find(), I expect it to search on the table payments, not on the table records, nor on the table orders.
What am I doing wrong? How can I get the classname of the class on which ::is called, instead of the class in which is was defined?
Important part is probably the get_class(), not being able to return the proper classname.

You can use get_called_class if you're using php 5.3 or higher. It gives you the class the static method is called on, not the one where the method is actually defined.
UPDATE
You need the class name of the class on which 'find' is called. You can fetch the class name in the find method and provide it as a parameter to the table (maybe rename it to getTableForClass($class)) method. get_called_class will give you the Payment class, the table method derives the table name and returns it:
class Record {
//Implementation is simplified, details out of scope for this question.
static public function getTableForClass($class) {
return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $class))."s";
}
static public function find($conditions) {
//... db-selection calls go here.
$className = get_called_class();
$tableName = self::getTableForClass($class);
var_dump($tableName);
}
}

Related

Calling multiple function in a single line in PHP

All my classes that connect to a database need to get values of custom columns from their respective tables. So instead of coding a function for each class, is there a way for me to implement a base class from which my classes extend and I can use that base class function to easily get and update data on my database (at least for simple data).
class Users extend BaseClass
{
private $table = "users";
private $columns = ["name", "email", "password"];
}
so from an outside function, I can access the email value like this
Users->where("name", "John")->getEmail();
or possibly
Users->where("name", "John")->get("email");
I could also use this method to update data to the database. The functions where should be universal so it should exist in BaseClass. (I know the database queries that I should use, what I want to know is how to call get after calling where and also possibly setting multiple where requirements).
Users->where("name", "John")->where("last_name", "Smith")->get("email");
I think you want something like this
abstract class BaseClass
{
private $where_clauses=[];
private $columns=[];
private $table='';
protected function setData($table,$cols){
$this->columns=$cols;
$this->table=$table;
}
public function where($key, $value){
$this->where_clauses[$key]=$value;
return $this;
}
public function get($col){
$sql='SELECT '.$col.' FROM '.$this->table.' WHERE';
$first=true;
foreach($this->where_clauses AS $key=>$val){
if(!$first) sql.=' AND ';
$first=false;
$sql.=$key.' = '.$val;
}
// RUN QUERY, Return result
}
}
Note that the where function returns a reference to $this, which is what let's you string the function calls together (not tested the code). This would also need some adapting to let you put two conditions on the same column.

Php Object oriented, Function calling

This is my php page persona.php:
<?php
class persona {
private $name;
public function __construct($n){
$this->name=$n;
}
public function getName(){
return $this->name;
}
public function changeName($utente1,$utente2){
$temp=$utente1->name;
$utente1->name=$utente2->name;
$utente2->name=$temp;
}
}
?>
The class persona is simple and just shows the constructor and a function that change two users name if called.
This is index.php:
<?php
require_once "persona.php" ;
$utente1 = new persona("Marcello");
print "First user: <b>". $utente1->getName()."</b><br><br>";
$utente2 = new persona("Sofia");
print "Second user: <b>". $utente2->getName()."</b><br>";
changename($utente1,$utente2);
print " Test after name changes: first user". $utente1->getName()."</b> second user". $utente2->getName();
?>
What I do not understand is how to call the changeName function from here.
I can understand where the confusion arises from...I think you are unsure if you should call changename on $utente1 or $utente2. Technically you can call it from either objects because they are both instances of Persona
But for clarity (and sanity), I would recommend converting the changeName function to a static function in its declaration:
public static function changeName($utente1,$utente2){
and then in your index.php you can call it as:
Persona::changename($utente1,$utente2);
From an architecture stamp point, this will help provide a better sense that the function is tied to the class of Persona, and objects can change swap names using that class function, as opposed to making it an instance function and then having any object execute it.
In your particular case you can call it as:
$utente1->changename($utente1,$utente2);
or
$utente2->changename($utente1,$utente2);
It doesn't matter which. As the method itself doesn't work with the classes properties (but only with the method parameters), you can call it from any object that exist.
But better (best practice, and better by design) is to develop a static method, as Raidenace already said, and call it like:
Persona::changename($utente1,$utente2);

PHP combine $this variable

How to combine two variables to obtain / create new variable?
public $show_diary = 'my';
private my_diary(){
return 1;
}
public view_diary(){
return ${"this->"}.$this->show_diary.{"_diary()"}; // 1
return $this->.{"$this->show_diary"}._diary() // 2
}
both return nothing.
Your class should be like following:
class Test
{
public $show_diary;
function __construct()
{
$this->show_diary = "my";
}
private function my_diary(){
return 707;
}
public function view_diary(){
echo $this->{$this->show_diary."_diary"}(); // 707
}
}
It almost looks from your question like you are asking about how to turn simple variables into objects and then how to have one object contain another one. I could be way off, but I hope not:
So, first off, what is the differnce between an object and a simple variable? An object is really a collection of (generally) at least one property, which is sort of like a variable within it, and very often functions which do things to the properties of the object. Basically an object is like a complex variable.
In PHP, we need to first declare the strucutre of the object, this is done via a class statement, where we basicaly put the skeleton of what the object will be into place. This is done by the class statement. However, at this point, it hasn't actually been created, it is just like a plan for it when it is created later.
The creation is done via a command like:
$someVariable= new diary();
This executes so create a new variable, and lays it out with the structure, properties and functions defined in the class statement.
From then on, you can access various properties or call functions within it.
class show_diary
{
public $owner;
public function __construct()
{
$this->owner='My';
}
}
class view_diary
{
public $owner;
public $foo;
public function __construct()
{
$this->foo='bar';
$this->owner=new show_diary();
}
}
$diary= new view_diary();
print_r($diary);
The code gives us two classes. One of the classes has an instance of the other class within it.
I have used constructors, which are a special type of function that is executed each time we create a new instance of a class - basically each time we declare a variable of that type, the __construct function is called.
When the $diary= new view_diary(); code is called, it creates an instance of the view_diary class, and in doing so, the first thing it does is assigns it's own foo property to have the value 'bar' in it. Then, it sets it's owner property to be an instance of show_diary which in turn then kicks off the __construct function within the new instance. That in turn assigns the owner property of the child item to have the value 'My'.
If you want to access single properties of the object, you can do so by the following syntax:
echo $diary->foo;
To access a property of an object inside the object, you simply add more arrows:
echo $diary->owner->owner;
Like this?
$diary = $this->show_diary . '_diary';
return $this->$diary();

Decorator case or not?

I have a contract "ArticleStorage" that every storage must be subscribe to be valid for model.
True, this is not the problem, my problem is: pagination ... or "results modification", in this case at fetchAll, i want modify its behavior but without adding parameters, etc
<?php
interface ArticleStorage
{
// public function insert();
// public function update();
// public function delete();
public function fetchAll();
}
class MySQLArticleStorage implements ArticleStorage
{
public function fetchAll()
{
// SELECT * FROM `articles`;
}
}
?>
How my model works.
class ArticlesModel
{
public function __construct(ArticleStorage $storage)
{
}
}
in this case, I expect a "ArticleStorage" but do not know which "Storage" was given, true ... and i want to paginate or apply a results modification, using the Storage.
class MySQLArticleResultsModifier
{
public function __construct(MySQLArticleStorage $storage)
{
}
public function fetchAll()
{
// ...
}
}
In case of a pagination, how i can modify ArticleStorage fetchAll and apply my modified query ?
Is there a case where your model demands that a fetchall on top of another fetchall is possible; I don't think so, infact this is how you decide if you need a decorator or not, by answering this question to yourself
Is the decorator function you are thinking of making works like a decoration{like a real decoration where you can put stars on your christmas tree {decoration1}, and some toys on your tree {decoration2} at the same instance? Otherwise there is no point in making a decorator pattern, The nature of decorator is to decorate the concrete implementations from outside world, and change the output, without being affected by the other decoration being applied to a concrete instance.
Now as to the current implementation, I think #mrhobo is quite right, your fetch function might look like
public function fetch($limit, $order,$sort)
A very smart fetch could also expect the user to send a hashtable of key-value , of the columnname = value of column by using which you can make your own select query on the fly.

Calling Parent Class From Sub Class PHP

$this->a->b->c->d calling methods from a superclass in php
Ive asked a question on this link I ve problem with this tecnique I am able to call the sub classes from a class
like this
$chesterx->db->query();
I wanna do get another class from sub class
for example
i want to query execute which was come from the sql class
ROOT
|
sql <--- chesterx ---> db
i wanna use the sql class from db
the problem i cant return the chesterx class from db class
/edit/
I have some classes like news, members, categories, db and query
and i did it like the link which was on the subject top
public function __construct(){
function __construct(){
if(!$this->db){
include(ROOT."/func/class/bp.db.class.php");
$this->db = new db;
}
if(!$this->chester){
include(ROOT."/func/class/bp.chester.class.php");
$this->db = new chester;
}
}
i called the db class with this code and now i am able to call and use the db class methods well
for example
i want to use a method from db
that method is containing a value which was returning a data from the chester class's method
i wish i were clarify myself
/edit/
is there anyway to do this?
I find Ionut G. Stan's solution good for your case, but you might also want to consider the factory/singleton pattern, though it's only good if your chesterx class is a global one, and only called once
The below snippet might be a solution, although I don't really like the circular reference. Try it and use it as you see fit. And by the way, what you are calling class and subclass are actually containing and contained class.
class Database
{
public $chesterx;
public function __construct($chesterx)
{
$this->chesterx = $chesterx;
}
}
class Sql
{
public $chesterx;
public function __construct($chesterx)
{
$this->chesterx = $chesterx;
}
}
class Chesterx
{
public $db;
public $sql;
public function __construct()
{
$this->db = new Database($this);
$this->sql = new Sql($this);
}
}

Categories