How to create a static variable and call it from another class? - php

I have a class called DB_Bookings, within that class I have a function called updated_variables() within this is a simple script to look at the date of a published post and change the name of a variable accordingly.
Doing this, throughout my app I intend to use the variable and it will change dynamically per post depending on the date created.
I am struggling to call the variables from within another class. Please see my working below:
class DB_Bookings {
...
public function updated_variables() {
global $post;
$compare_date = strtotime( "2018-05-22" );
$post_date = strtotime( $post->post_date );
if($compare_date > $post_date) {
$weddingNameVariable = 'db-bookingsweddingname';
...
} else {
$weddingNameVariable = 'weddingName';
}
}
} // end DB_Bookings class
Then in my other class (in a file called class-db-bookings-admin.php)
class DB_Bookings_Admin {
...
public function save_metabox( $post_id, $post ) {
...
update_post_meta( $post_id, DB_Bookings::updated_variables($weddingNameVariable), $db_bookingsnew_weddingname );
...
}
} // end Class DB_Bookings_Admin
The idea here is that I can echo out the variable set in my DB_Bookings class and it can change based on the post date (this is essentially compensating for legacy variables as I overhaul the coding of the app).
However, it doesn't appear to be saving and I'm getting the following error
[22-May-2018 19:29:43 UTC] PHP Notice: Undefined variable: weddingNameVariable in /var/www/html/wp-content/plugins/db-bookings/admin/class-db-bookings-admin.php on line 853

Another approach based on comments.
class WeddingVariables {
//add all of the variables needed to this class
//you could create getters/setters to manage this data
$variableA = "data";
//get the variable
public function get_variable_a() {
return $this->variableA;
}
//set the variable
public function set_variable_a( $value ) {
$this->variableA = $value;
}
}
//a global variable
$WeddingVariables = new WeddingVariables();
//admin class
class DB_Bookings_Admin {
public function save_metabox( $post_id, $post ) {
global $WeddingVariables; //now we can access this within this method
//get the value of a variable from the class
$someVariable = $WeddingVariables->get_some_variable();
}
}

All I'm seeing that you're missing here is declaring your variable and treating it as static within the class itself.
public static $weddingNameVariable;
if($compare....)
self::$weddingNameVariable;
That's the basic bit you'll want to change, but there's a somewhat more complicated bit that's not correct: you're treating a non-static function as if it's static. So you may need to change your updated_variables function to be static itself. I also see that you're trying to do $post->post_date immediately after declaring global $post; but without initializing it to have any value. If you are trying to access post data sent from the client, try $_POST['some-key-here'] which is defined by PHP and accessible anywhere.
Once that's all straightened out, you can either have your updated_variables function return the new value you've set, or call the function the line before and then access the variable using DB_Bookings::$weddingNameVariable.

I notice a couple of things here. First, updated_variables() is not a static method, although you are calling it as a static method DB_Bookings::updated_variables(). To use that method statically, you would need to make it a static method via public static function updated_variables(). That is a discussion in itself however.
There are many ways to accomplish what you want, but you could do it with a global variable.
<?php
//this is global
$weddingNameVariable = false;
class DB_Bookings {
public function updated_variables() {
global $weddingNameVariable;
//now you can read/update this variable from within this method
}
}
class DB_Bookings_Admin {
public function save_metabox( $post_id, $post ) {
global $weddingNameVariable;
//now you can read/update this variable from within this method.
}
}
This may not be the OOP approach you are looking for, as you could utilize a static variable, but if that value you needs to change often, you'd be better managing it via other options in my opinion.

Related

Access a class within a function

Using as an example the class defined here
class Testclass {
private $testvar = "default value";
public function setTestvar($testvar) {
$this->testvar = $testvar;
}
public function getTestvar() {
return $this->testvar;
}
function dosomething()
{
echo $this->getTestvar();
}
}
$Testclass = new Testclass();
$Testclass->setTestvar("another value");
$Testclass->dosomething();
I would like to add inside a function "one more value", like this:
function test_function() {
$Testclass->setTestvar("one more value");
}
But it doesn´t work. I gives the error message undefined variable Testclass. In order to make it work, I have to define the variable as global within the function, like this:
function test_function() {
global Testclass;
$Testclass->setTestvar("one more value");
}
I am quite new to PHP, but it seems rather strange to me this way of using it. From the main PHP file it´s already defined, but when I use it from a function I have to define again.Basically what I am trying to do is to create a class that creates a new file and adds strings to it from different functions. Is there not a better way? Any suggestions? Many thanks in advance.
One way is to use singleton
MyClass::getInstance()->doSomethingUsefull();
Sometimes you can use static method
MyClass::doIt();
Functions have their own private variable scope. So (for example) you can use $i in a function without worrying about it screwing up another $i somewhere else in the program. If you want to have a function perform actions on an already-existing object, just pass the object as a parameter to the function:
function test_function(Testclass $testclass)
{
$testclass->setTestvar("one more value");
}
Then call it with your object:
$Testclass = new Testclass();
test_function($Testclass);
Note: If the functions you're defining outside the class are tightly related to the class, then you probably want to define them as methods inside the class instead of separate stand-alone functions.

Why a global variable isn't recognized?

I want to call for a variable defined at a some point in the code. I use global keyword but it seems variable isn't recognized. When I set variable locally it works just fine. (it is the $title variable, it receives value of a static function of some object)
THIS ONE WORKS:
class Book {
public function represent() {
$titles = Title::all_by_id();
$title = $titles[$this->title_id];
return $title->represent().'_'.$this->id;
}
}
THIS ONE DOESN'T:
$titles = Title::all_by_id();
in another file
class Book {
public function represent(){
global $titles;
$title = $titles[$this->title_id];
return $title->represent().'_'.$this->id;
}
}
It sends an error:
PHP Fatal error: Call to a member function represent() on a non-object in
What are possible problems here?
I solved it, it was the problem that I set the $titles variable in a different subcontext of the main context than where Book class was defined
I solved the problem when I changed the place where I was defining that variable, I've put it in the main context.

PHP - architecture, issue with variables scope

I'm writing now an app, which is supposed to be as simple as possible. My controllers implement the render($Layout) method which just does the following:
public function render($Layout) {
$this->Layout = $Layout;
include( ... .php)
}
I don't really understand the following problem: in my controller, I define a variable:
public function somethingAction() {
$someVariable = "something";
$this->render('someLayout');
}
in the php view file (same I have included in the render function) I try to echo the variable, but there is nothing. However, if I declare my action method like this:
public function somethingAction() {
global $someVariable;
$someVariable = "something";
$this->render('someLayout');
}
and in my view like this:
global $someVariable;
echo $someVariable;
it does work. Still it is annoying to write the word global each time.
How can I do this? I'd rather not use the $_GLOBAL arrays. In Cake PHP, for example, there is a method like $this->set('varName', $value). Then I can just access the variable in the view as $varName. How is it done?
From the PHP Manual on include:
When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.
When you do
public function somethingAction() {
$someVariable = "something";
$this->render('someLayout');
}
the $someVariable variable is limited to the somethingAction() scope. Calling your render() method will not magically make the variable available in render(), because the render() method has it's own variable scope. A possible solution would be to do
public function somethingAction() {
$this->render(
'someLayout',
array(
'someVariable' => 'something'
)
);
}
and then change render() to
public function render($Layout, array $viewData) {
$this->Layout = $Layout;
include( ... .php)
}
You will then have access to $viewData in the included file, given that you are not trying to use it in some other function or method, e.g. if your included file looks like this:
<h1><?php echo $viewData['someVariable']; ?></h1>
it will work, but if it is looks like this:
function foo() {
return $viewData['someVariable'];
}
echo foo();
it will not work, because foo() has it's own variable scope.
However, a controller's sole responsibility is to handle input. Rendering is the responsibility of the View. Thus, your controller should not have a render() method at all. Consider moving the method to your View class and then do
public function somethingAction() {
$view = new View('someLayout');
$view->setData('someVariable', 'something');
$view->render();
}
The render() method of your View object could then be implemented like this:
class View
…
$private $viewData = array();
public function setData($key, $value)
{
$this->viewData[$key] = $data;
}
public function render()
{
extract($this->viewData, EXTR_SKIP);
include sprintf('/path/to/layouts/%s.php', $this->layout);
}
The extract function will import the values of an array in the current scope using their keys as the name. This will allow you to use data in the viewData as $someVariable instead of $this->viewData['someVariable']. Make sure you understand the security implications of extract before using it though.
Note that this is just one possible alternative to your current way of doing things. You could also move out the View completely from the controller.
Using global you're implicitly using the $_GLOBALS array.
A not recommended example, because globals are never a good thing:
function something() {
global $var;
$var = 'data';
}
// now these lines are the same result:
echo $_GLOBALS['var'];
global $var; echo $var;
Why don't you use simply the $this->set function?
public function render($Layout) {
$this->Layout = $Layout;
include( ... .php)
}
public function somethingAction() {
$this->set('someVariable', "something");
$this->render('someLayout');
}
// in a framework's managed view:
echo $someVariable;
I'm sorry not to know your framework in detail, but that makes perfectly sense.
Actually how it's done: There is a native extract function, that loads an associative array into the current symbol table:
array( 'var0' => 'val0', 'var1' => 'val1')
becomes
echo $var0; // val0
echo $var1; // val1
That's most likely 'what happens'.

How to Pass a function to a class in php

I have a class that generates data based on a few things. I would like to format that data from the outside. So I am trying to pass a function into the class so that it would format that data. I have looked at many examples, but it seems this is unique.
Can anybody give an idea of how to do this? The following code gives an error.
<?php
class someClass {
var $outsideFunc; // placeholder for function to be defined from outside
var $somevar='Me'; // generated text
function echoarg($abc){
$outsideFunc=$this->outsideFunc; // bring the outside function in
call_user_func($outsideFunc,$abc); // execute outside function on text
echo $abc;
}
}
function outsidefunc($param){ // define custom function
$param='I am '.$param;
}
$someClass=new someClass();
$someClass -> outsideFunc = 'outsideFunc'; // send custom function into Class
$someClass -> echoarg($someClass->somevar);
$someClass -> outsidefunc = 'outsidefunc';
In PHP, function names are not case sensitive, yet object property names are. You need $someClass->outsideFunc, not $someClass->outsidefunc.
Note that good OOP design practice calls for the use of getter and setter methods rather than just accessing properties directly from outside code. Also note that PHP 5.3 introduced support for anonymous functions.
Yeah. You are right. Now there is no error. But it does not work either.
By default, PHP does not pass arguments by reference; outsidefunc() does not actually do anything useful. If you want it to set $param in the caller to something else, and do not want to just return the new value, you could change the function signature to look like this:
function outsidefunc(&$param) {
You would also need to change the way you call the function, as call_user_func() does not allow you to pass arguments by reference. Either of these ways should work:
$outsideFunc($abc);
call_user_func_array($outsideFunc, array(&$abc));
Why not pass your function as an argument?
<?php
class someClass {
public $somevar="Me";
public function echoarg($abc,$cb=null) {
if( $cb) $cb($abc);
echo $abc;
}
}
$someClass = new someClass();
$someClass->echoarg($someClass->somevar,function(&$a) {$a = "I am ".$a;});
i am not sure what exactly you are looking for, but what i get is, you want to pass object in a function which can be acheive by
Type Hinting in PHP.
class MyClass {
public $var = 'Hello World';
}
function myFunction(MyClass $foo) {
echo $foo->var;
}
$myclass = new MyClass;
myFunction($myclass);
OP, perhaps closures are what you're looking for?
It doesn't do EXACTLY what you're looking for (actually add function to class), but can be added to a class variable and executed like any normal anonymous function.
$myClass->addFunc(function($arg) { return 'test: ' . $arg });
$myClass->execFunc(0);
class myClass {
protected $funcs;
public function addFunc(closure $func) {
$this->funcs[] = $func;
}
public function execFunc($index) { $this->funcs[$index](); } // obviously, do some checking here first.
}

Assigning a function's result to a variable within a PHP class? OOP Weirdness

I know you can assign a function's return value to a variable and use it, like this:
function standardModel()
{
return "Higgs Boson";
}
$nextBigThing = standardModel();
echo $nextBigThing;
So someone please tell me why the following doesn't work? Or is it just not implemented yet? Am I missing something?
class standardModel
{
private function nextBigThing()
{
return "Higgs Boson";
}
public $nextBigThing = $this->nextBigThing();
}
$standardModel = new standardModel;
echo $standardModel->nextBigThing; // get var, not the function directly
I know I could do this:
class standardModel
{
// Public instead of private
public function nextBigThing()
{
return "Higgs Boson";
}
}
$standardModel = new standardModel;
echo $standardModel->nextBigThing(); // Call to the function itself
But in my project's case, all of the information stored in the class are predefined public vars, except one of them, which needs to compute the value at runtime.
I want it consistent so I nor any other developer using this project has to remember that one value has to be function call rather then a var call.
But don't worry about my project, I'm mainly just wondering why the inconsistency within PHP's interpreter?
Obviously, the examples are made up to simplify things. Please don't question "why" I need to put said function in the class. I don't need a lesson on proper OOP and this is just a proof of concept. Thanks!
public $nextBigThing = $this->nextBigThing();
You can only initialize class members with constant values. I.e. you can't use functions or any sort of expression at this point. Furthermore, the class isn't even fully loaded at this point, so even if it was allowed you probably couldn't call its own functions on itself while it's still being constructed.
Do this:
class standardModel {
public $nextBigThing = null;
public function __construct() {
$this->nextBigThing = $this->nextBigThing();
}
private function nextBigThing() {
return "Higgs Boson";
}
}
You can't assign default values to properties like that unless that value is of a constant data type (such as string, int...etc). Anything that essentially processes code (such as a function, even $_SESSION values) can't be assigned as a default value to a property. What you can do though is assign the property whatever value you want inside of a constructor.
class test {
private $test_priv_prop;
public function __construct(){
$this->test_priv_prop = $this->test_method();
}
public function test_method(){
return "some value";
}
}
class standardModel
{
// Public instead of private
public function nextBigThing()
{
return "Higgs Boson";
}
}
$standardModel = new standardModel(); // corection
echo $standardModel->nextBigThing();

Categories