I would like to generate an log file. Therefor I have created a static class called log with an method called write:
class log {
public static function write($info) {
// file writing
}
}
In this function i would like to know from which class the method write is called (automatically):
log::write("Testinformation");
I have already tried with: get_called_class - but this gives me only "log" instead of the "real" called class...
Is there any way to automatically retrieve the called class?
$offset = 1;
$backtrace = debug_backtrace();
$caller = array();
if(isset($backtrace[$offset])) {
$backtrace = $backtrace[$offset];
if(isset($backtrace['class'])) {
$caller['class'] = $backtrace['class'];
}
if(isset($backtrace['function'])) {
$caller['function'] = $backtrace['function'];
}
}
No you have info about calling class and method or function. You can also use function I wrote long time ago
<?php
function getCaller($offset = 0) {
$baseOffset = 2;
$offset += $baseOffset;
$backtrace = debug_backtrace();
$caller = array();
if(isset($backtrace[$offset])) {
$backtrace = $backtrace[$offset];
if(isset($backtrace['class'])) {
$caller['class'] = $backtrace['class'];
}
if(isset($backtrace['function'])) {
$caller['function'] = $backtrace['function'];
}
}
return $caller;
}
?>
You can't retrieve the class that called it.
use something like:
define("log_tag", "myclass")
at the start of the file, and through out the rest of the file call:
log::write(log_tag, "testinformation");`
I think it would be easier to add the class name at the call of the method :
class Foo
{
public function bar()
{
// do something ...
log::write(get_called_class().': blablabla...');
}
}
Related
PHP allows for variables to hold functions like so:
$f = function($a,$b) {
print "$a $b";
};
$f("Hello","World!"); //prints 'Hello World!'
This works just fine for me. I'm trying to pass a function into a class and set an instance variable to hold that function but with little luck:
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print $this->distanceFunc(1,7); //exceptions and errors abound
}
}
$func = function($a,$b) {
return abs($a-$b);
}
$c = new Clusterer($func);
Am I doing something wrong here? The error is that the function doesn't exist so my guess currently is that it looks for a class function with that name (which there isn't one) and then gives up rather than looking for variables as well... how can I make it view the $this->distanceFunc as a variable?
EDIT:
So after the advice from the answers below, I found a solution which was the make a function to wrap the invocation. For example my class is now:
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print $this->distanceFunc(1,7); //exceptions and errors abound
}
private function distanceFunc($a,$b) {
$holder = $this->distanceFunc;
return $holder($a,$b);
}
}
$func = function($a,$b) {
return abs($a-$b);
}
$c = new Clusterer($func);
and this works great. Php looks for functions first and can only tell if it is a variable by context I guess is the moral of this story.
Your code doesn't work because PHP interprets $this->distanceFunc(1,7) as a class method, but you can do the following:
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print call_user_func_array($this->distanceFunc, array(1, 7));
// print $this->distanceFunc(1,7); //exceptions and errors abound
}
}
$func = function($a,$b) {
return abs($a-$b);
};
$c = new Clusterer($func);
http://sandbox.onlinephpfunctions.com/code/cdc1bd6bd50f62d5c88631387ac9543368069310
In PHP, methods and properties of an object occupy separate namespaces. This is different from JavaScript, for example, where foo.bar = function() {} is a perfectly valid way of defining a method.
Consequently, $this->distanceFunc(1,7); looks for a method named distanceFunc on the current class, and the classes it inherits from, but never looks for the property which you happen to have given the same name.
One solution is to force PHP to look up a property, then execute it, e.g. $foo = $this->distanceFunc; $foo(1,7) or call_user_func($this->distanceFunc, 1, 7)
Another would be to define the magic method __call on your class, which gets run whenever a non-existent method is referenced. Something like this ought to work (I don't have an easy way to testright now):
function __call($func, $args) {
if ( property_exists($this, $func) && is_callable($this->$func) ) {
return call_user_func_array($this->$func, $args);
}
}
Note that this still isn't the same as a real method, for instance in terms of access to private properties.
It looks like you're going for a strategy pattern here. IE you want to be able to inject different methods for calculating distance? If so there is a more "sane" way to do it.
You can define an interface to the classes you will use to store the strategy method ensuring that the class will always have the method calculate() for example which would be your distance calculation function. Then in the constructor of your Clusterer class, type check against the interface in the parameter and call calculate() on the object passed in.
Looks like this:
interface Calculateable
{
public function calculate();
}
class MyDistanceCalculator implements Calculateable
{
public function calculate()
{
// Your function here
}
}
class Clusterer
{
protected $calc;
public function __construct(Calculateable $calc)
{
$this->calc = $calc;
$this->calc->calculate();
}
}
$myClusterer = new Clusterer(new MyDistanceCalculator());
Because you defined an interface, any object you pass in will have the calculate() function
In HHVM, you can do this:
<?php
class Foo
{
public function __construct()
{
$this->bar = function() { echo "Here\n"; };
($this->bar)();
}
}
new Foo();
But it's not yet supported in PHP. But, it will be in PHP 7 (there will be no release named PHP 6).
PHP doesn't have first class functions. In JavaScript if you returned a function you could do this: myFunctionThatReturnsAFunction()(1,2), but not in PHP.
<?php
class Clusterer {
private $distanceFunc;
public function __construct(Closure $f) {
$this->distanceFunc = $f;
}
public function getDistFunc()
{
return $this->distanceFunc;
}
}
$func = function($a,$b) {
return abs($a-$b);
};
$c = new Clusterer($func);
$a = $c->getDistFunc();
echo $a(1,2);
Take a look at call_user_func
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print call_user_func($this->distanceFunc, 1, 7); //works too ;)
}
}
$func = function($a,$b) {
return abs($a-$b);
};
$c = new Clusterer($func);
Don't ask me what is the difference, but it works the way you want (One of the reasons i hate this language)
I'm currently trying to get back into object oriented programming How do i get my array inside my class? Global doesn't seam to cut it.
<?
$systems = file_get_contents('https://api.eveonline.com/map/Sovereignty.xml.aspx');
$systems = explode("<row ",$systems);
//print_r($systems);
for ($i = 1; $i <= count($systems); $i++) {
//system name
$systemnames=explode("solarSystemName=",$systems[$i]);
$systemnames=explode('"',$systemnames[1]);
$systemnames=$systemnames[1];
//system id
$systemid=explode("solarSystemID=",$systems[$i]);
$systemid=explode('"',$systemid[1]);
$systemid=$systemid[1];
$systembyid[$systemid]=$systemnames;
$systembyname[$systemnames]=$systemid;
}
class Systems{
public function __construct()
{
global $systembyid;
global $systembyname;
}
function getSystems($system)
{
if (is_numeric($system) && $systembyid[$system]) {
return $systembyid[$system];
}
elseif($systembyname[$system]){
return $systembyname[$system];
}
else{
return "Error: Invalid system id or name";
}
}
}
?>
Try passing the values into the constructor like this, also if you use the & you are just passing a reference and not making a copy of the whole array.
class Systems{
private $sysyembyid;
private $systembyname;
public function __construct(&$systembyid, &$systembyname)
{
$this->systembyid = $systembyid;
$this->systembyname = $systembyname;
}
function getSystems($system){
if(is_numeric($system) && $this->systembyid[$system]){
return $this->systembyid[$system];
}
elseif($this->systembyname[$system]){
return $this->systembyname[$system];
}
else{
return "Error: Invalid system id or name";
}
}
}
I prefer to use Dependency Injection. Dependency Injection is when you inject your object's dependencies via the constructor. This ensures that the object will have its dependencies at creation.
class Systems {
protected $systembyid;
protected $systembyname;
public function __construct($systembyid, $systembyname)
{
$this->systembyid = $systembyid;
$this->systembyname = $systembyname;
}
public function getSystems($system) {
//Access them with $this-> like below
$this->systembyid[$system];
$this->systembyname[$system];
}
}
Note If you want to be able to modify $systembyid and $systembyname outside of the class, and see the changes within the class, you can pass references to __construct() instead, by specifying the parameters as references:
public function __construct(&$systembyid, &$systembyname)
{
$this->systembyid = $systembyid;
$this->systembyname = $systembyname;
}
Alternatively, you can pass them as parameters to your getSystems() method.
class Systems() {
public function getSystems($system, $systembyid, $systembyname) {
//Do stuff
}
}
The main drawbacks with this approach is that you always have to pass them as parameters to the method, and the method signature could get quite long.
You either need to use the global key word with var in the function where you use it, in this case getSystems() (bad) or pass them into the constructor or the function where you use them, or set them:
Probably the most common case:
public function __construct($s1, $s2)
{
$this->systembyid = $s1
$this->systembyname = $s2
}
//then use $this->systembyid etc in other functions
Or better yet, why not put all that processing code in a function off the class like processSystems() and set the vars there:
public function processSystems($file) {
$systems = file_get_contents($file);
$systems = explode("<row ",$systems);
//print_r($systems);
for ($i = 1; $i <= count($systems); $i++) {
//system name
$systemnames=explode("solarSystemName=",$systems[$i]);
$systemnames=explode('"',$systemnames[1]);
$systemnames=$systemnames[1];
//system id
$systemid=explode("solarSystemID=",$systems[$i]);
$systemid=explode('"',$systemid[1]);
$systemid=$systemid[1];
$systembyid[$systemid]=$systemnames;
$systembyname[$systemnames]=$systemid;
}
$this->systembyid = $systemnames;
$this->systembyname = $systemid;
}
Aside from that, I would say look into simple_xml or DOM for the XML parsing.
Also, you are storing the exact same data in each array. Just use one and either lookup the key or the value.
<?php
try{
$test = new TestAccessModifiers("2345","xyz","vfd","a0001","99","67"); /*invoking the class*/
var_dump($test->calculate());
}
catch(Exception $e){
echo $e->getMessage();
}
?>
<?php
class TestAccessModifiers {
function TestAccessModifiers($user_p,$user_fn,$user_ln,$user_id,$marks1,$marks2) {
echo "hello1";
$this->user_phone=$user_p;
$this->user_fname=$user_fn;
$this->user_lname=$user_ln;
$this->user_id=$user_id;
$this->marks1=$marks1;
$this->marks2=$marks2;
echo $this->marks1;
}
private $additional_marks = 10;
public static function calculate(){
return $this->marks1+$this->marks2+$this->getAdditionalmarks();
}
public function getAdditionalmarks(){
return $this->additional_marks;
}
}
?>
Above is the simple code i am trying to run... but i am unable to call TestAccessModifiers
I have tried using _constructor too
Rename your TestAccessModifiers function to __construct.
public function __construct($user_p,$user_fn,$user_ln,$user_id,$marks1,$marks2) {
echo "hello1";
$this->user_phone = $user_p;
$this->user_fname = $user_fn;
$this->user_lname = $user_ln;
$this->user_id = $user_id;
$this->marks1 = $marks1;
$this->marks2 = $marks2;
echo $this->marks1;
}
Then, remove static from calculate function.
It should then works..
Reference: http://php.net/manual/en/language.oop5.decon.php
if you are calling the class in another php page, make sure you include it like this.
include('/path/to/your/class.php');
$test = new TestAccessModifiers("2345", "xyz", "vfd", "a0001", "99", "67");
or if you are instantiating the object within the same file then place the instantiation code below your class.
class TestAccessModifiers {
public function __construct($user_p, $user_fn, $user_ln, $user_id, $marks1, $marks2) {
echo "hello1";
$this->user_phone = $user_p;
$this->user_fname = $user_fn;
$this->user_lname = $user_ln;
$this->user_id = $user_id;
$this->marks1 = $marks1;
$this->marks2 = $marks2;
echo $this->marks1;
}
private $additional_marks = 10;
public function calculate() {
return $this->marks1 + $this->marks2 + $this->getAdditionalmarks();
}
public function getAdditionalmarks() {
return $this->additional_marks;
}
}
try {
$test = new TestAccessModifiers("2345", "xyz", "vfd", "a0001", "99", "67"); /*invoking the class*/
var_dump($test->calculate());
} catch (Exception $e) {
echo $e->getMessage();
}
you have defined a static method in your class, and have used the pseudo variable $this inside of the static method, which PHP does not allow. since static method is treated out of object context in PHP. you need to remove the static method to use $this
First: Which PHP version you have?
Second: Are you including the class file in the file that you are instancing?
Third: Your function "calculate" is static, then, you can't access to it from an instance and it have no way to read or write properties non-statics.
Try TestAccessModifiers::calculate(); and put in a simple return "Hello World"
Greetings.
What version of PHP are we talking about?
First thing comes to mind: did you add it to autoload ?
I would use the __constructor methode as initiator routine of the class.
public static function calculate() {
return $this - > marks1 + $this - > marks2 + $this - > getAdditionalmarks();
}
You can't operate on $this from a static context. Make this method non-static, or adjust the other variables to be static, whichever suits your context.
How do I see variables from another function in the same class?
Here is the problem i have:
class slike {
public function __construct($dire) {
$this->dire=$dire;
}
function skupljanjeslika() {
$slike = array();
$handler = opendir($this->dire);
while ($file = readdir($handler)) {
if ($file != "." && $file != "..") {
$slike[] = $file;
}
}
closedir($handler);
return $slike; // **Array i want to use!**
}
function prikazradnomslike() {
$slike; // Here is the array from first function, but I can't see it here
$rezultat = count($slike)-1;
$koliko=rand(0, $rezultat);
$slika=$slike[$koliko];
return $slika;
}
}
did you try to do this :
$slike = $this->skupljanjeslika();
Or if you method skupljanjeslika is used before, try this :
In your class, add a var :
protected $slike;
In skupljanjeslika replace the return by this :
$this->slike = $slike;
And in prikazradnomslike, do this :
$slike = $this->slike;
To be more efficient, you can definitly do this :
class slike {
protected $slike;
public function __construct($dire) {
$this->dire=$dire;
}
function skupljanjeslika() {
$slike = array();
$handler = opendir($this->dire);
while ($file = readdir($handler)) {
if ($file != "." && $file != "..") {
$slike[] = $file;
}
}
closedir($handler);
$this->slike = $slike;
}
function prikazradnomslike() {
$rezultat = count($this->slike)-1;
$koliko=rand(0, $rezultat);
$slika=$this->slike[$koliko];
return $slika;
}
}
Add a variable to the class:
class slike
{
$protected $slike;
public function __construct($dire) {
...
Access it like this:
$this->slike;
You need to define your variable as a class variable, i suggest to read this to see how to declare class variables.
class slike {
...
function prikazradnomslike()
{
$slike = $this->skupljanjeslika();
return $slike[ array_rand($slike, 1) ];
}
}
see http://docs.php.net/return and http://docs.php.net/array_rand
You can either call skupljanjeslika() from where you want your return value like this: $slike = $this->skupljanjeslika(); or you can pass in the array as a parameter if you want to call it from somewhere else:
function prikazradnomslike($slike)
{
$rezultat = count($slike)-1;
$koliko=rand(0, $rezultat);
$slika=$slike[$koliko];
return $slika;
}
You could have a private property $slike in your class, set it in your slike::skuplanjeslika() and use it in your slike::prikazrandomslike(). Another option is to pass $slike as an argument to slike::prikazrandomslike:
class slike
{
public function __construct($dire)
{
$this->dire=$dire;
}
function skupljanjeslika()
{
$slike = array();
$handler = opendir($this->dire);
while ($file = readdir($handler)) {
if ($file != "." && $file != "..") {
$slike[] = $file;
}
}
closedir($handler);
return $slike; // **Array i want to use!**
}
function prikazradnomslike($slike)
{
$rezultat = count($slike)-1;
$koliko=rand(0, $rezultat);
$slika=$slike[$koliko];
return $slika;
}
}
$photos = new slike('mydir');
$photos->prikazrandomslike($photos->skuplanjeslika());
The issue you're having has to do with "scope" ( http://php.net/manual/en/language.variables.scope.php ). A variable is not accessible outside of the function in which it was originally declared.
If you want access to a variable anywhere within your script there are a number of ways to accomplish this. You can use global variables (not recommended in most cases) or declare them as part of a class (these can be static or not - more on that farther down the post).
A variable declared inside of a class will look something like this:
class myClass {
public $var1;
protected $var2;
private $var3;
public function foo() {
return $this->var1;
}
}
Make a note of public, private and protected, as these are very important keywords.
A private variable within a class is only accessible within that class - it will not be inherited by any children, nor can it be accessed directly by an instance of the object (i.e. $myClassObj->var1)
A protected variable will be inherited by child classes, but has the same access restrictions when using instances of the object.
A public variable is accessible directly and will be inherited.
In order to access any of these variables within the class, simply refer to it using the $this variable.
E.G.:
$this->$var1;
Now, if you declare a variable as static it will be available in memory at all times and accessible via the scope resolution operator (::). HOWEVER private and protected variables will not be directly accessible (same rules apply as before).
myClass::$var1 = 4; // this works fine, and sets $var1 to 4 across ALL instances of myClass
myClass::$var2 = 3; // this WILL NOT WORK - protected variable.
If you need to access a static variable within the class you must refer to it using the scope resolution operator and the keyword self.
class myClass {
public static $var1;
function bar() {
return self::$var1;
}
}
The following is my simplified code
<?php
$database = new db();
$file = new file();
$input = new input();
$output = new output();
$data = "SELECT * FROM table;";
$input->page($data);
class db {
public function queryExecute($var) {
$var = $this->queryEncode($var);
$var = $this->querySubmit($var);
return $var;
}
public function queryEncode($var) {
// Do somthing
return $var;
}
public function querySubmit($var) {
// Do somthing
return $var;
}
}
The issue is when I add this to the code:
class input {
public function page($data) {
// Do something
$pageQuery = db::queryExecute($data);
}
}
With this, there are two things I have to do. First, I have to hide the errors for the db::queryExecute($data); code if the server is set to strict. And now for the second problem. I can't seem to use this line of code (which is the only way I have yet found possible for referencing other classes besides using Abstract) if the class that is being referenced is referencing yet another class but this time within it's own class.
For better explanation, the procedure is as follows:
Grab the $data variable and send it to the $input->page() function ( $input->page($data) ).
Referencing the db class, the $input->page() function sends the information onto the $database->queryExecute() function by means of the db::queryExecute() format ( db::queryExecute($data) ).
But because we are using the ::, when $database->queryExecute() references $database->queryEncode() and $database->querySubmit() using $this-> operator ( $this->queryEncode() and $this->querySubmit() ), $this-> currently belongs to $input-> and not $database->.
So what's the solution... Reference the other class differently (instead of ::)? Use a $_GLOBAL variable when I define my classes? Use something other than $this->? Configure all of the classes to use ABSTRACT/EXTENDS (or INTERFACE)?
The following error outputted refers to $var = $this->queryEncode($var);:
Fatal error: Call to undefined method input::querySubmit() in C:\[...]\global.php on line 12
Do not make static call to not static function. Pass $db instance to page, or provide global access to the database (via global registry, singleton or other method). But best, pass the dependency - the database instance, to the method.
<?php
$database = new db();
$file = new file();
$input = new input($database);
$output = new output();
$data = "SELECT * FROM table;";
$input->page($data);
class db {
public function queryExecute($var) {
$var = $this->queryEncode($var);
$var = $this->querySubmit($var);
return $var;
}
public function queryEncode($var) {
// Do somthing
return $var;
}
public function querySubmit($var) {
// Do somthing
return $var;
}
}
class input {
protected $_database;
public function __construct($database) {
$this->_database = $database;
}
public function page($data) {
// Do something
$pageQuery = $this->_database->queryExecute($data);
}
}
You can only use the double-colon operator on static, constant, or overridden properties or methods of a class. See the documentation on this. Use -> instead.