Good evening,
In my app that I'm currently developing, I have a class that handles multilinguism. It does so by externally loading an associative array, where a translation source would be defined something like this:
'Source input' => 'Zdroj vstupního'
Currently this works flawlessly by addressing and using the class the following way:
$lang = new Lang('Czech');
print $lang->_('Source input'); // output: "zdroj vstupního"
However, I want to have this in a short cut function that does not depend on an instance of the "Lang" class. I've tried experimenting with static methods, but so far I'm out of luck.
Pseudo code of what I want to achieve.
$lang = new Lang('Czech');
$lang->setCurrent('contact_us'); // loads the language file for contact_us
<p>
<?php print _('Source input'); ?> // output: "zdroj vstupního"
</p>
A point in the right direction would be great. Thanks!
You can access the global $lang variable from your _ function if you use a global $lang statement:
<?php
class Lang
{
function _($str)
{
return 'Zdroj vstupního';
}
}
function _($str)
{
global $lang;
return $lang->_($str);
}
$lang = new Lang('Czech');
print _('Source input');
?>
Alternatively you could use a static variable in the Lang class instead of creating an instance of the class. It's a little cleaner this way as you avoid having to create a $lang variable in the global namespace.
<?php
class Lang
{
static $lang;
function setCurrent($lang)
{
self::$lang = $lang;
}
}
function _($str)
{
if (Lang::$lang == 'Czech')
{
return 'Zdroj vstupního';
}
}
Lang::setCurrent('Czech');
print _('Source input');
?>
Related
I just want to ask if its possible to call variables on class to another page of the site. I have tried calling the function's name and inside the parenthesis. I included the variable found inside that function e.g:
<?php
$loadconv -> loadmsg($msgReturn);
echo $loadconv;
?>
But it didn't work.
Do you want something like this?
class Load
{
public $msgReturn;
__construct()
{
}
public function loadMsg($param)
{
$this->msgReturn = $param;
}
}
Then you could do
$loadConv = new Load();
$loadConv->loadMsg('just a string');
echo $loadConv->msgReturn; // 'just a string'
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'.
I have a class which contains a method to load a view. This works perfect and the page is loaded correctly! The problem I'm having is that I can't seem to figure out a way to pass variables to the view that my method currently tries to load. How can I go by passing variables to the page? Is there a way I can manipulate my current code to make this work? Or am I going in the complete opposite direction?
Controller Class:
<?php
class Controller {
private $args = array();
public function view($page, $args = null) {
if ($args !== null) {
$this->args = $args;
extract($this->args);
}
$page = VIEWS . $page . '.php';
$template = $this->getTemplate($page);
echo $template;
}
private function getTemplate($file) {
ob_start();
include($file);
$template = ob_get_contents();
ob_end_clean();
return $template;
}
}
?>
Controller:
<?php
class Page extends Controller {
public function person($age) {
$data['age'] = $age;
$this->view('person', $data);
}
}
?>
View Contents:
</h1>My name is Dennis. My age is: <?php echo $age; ?></h1>
The end result is an undefined variable ($age).
The variables which you extract in view() are not available in getTemplate(). It is a different scope. You should instead extract them in the same method that does the rendering.
Also, what you have there is not an MVC view. It's just a template. A view in MVC is an instance which is responsible for UI logic. It should be requesting the information, that it needs, from model layer and then, if a response is not simply a HTTP location header, creating the HTML using multiple templates.
Try this:
</h1>My name is Dennis. My age is: <?php echo $data['age']; ?></h1>
The easiest way is to pass down the $args variable to getTemplate, and do the extract method in the getTemplate method
private function getTemplate($file, $args = null) {
if ($args !== null) {
extract($args);
}
ob_start();
include($file);
$template = ob_get_contents();
ob_end_clean();
return $template;
}
when you include and capture the the output, that php file is executed, so before inclusion all the variables must be present
If you dont want to pass down variables you can use $this->args inside of the template
You extract the variables in a different method than where you include the template. If you want to use plain variables in your templates, make sure that they are extracted in the same scope.
I have a function called
chewbacca() {
include('external.php');
echo $lang[1];
...
}
The file external.php contains all the $lang array. However, since I have to execute the function thousands of times, I would like to include only once the file. If I include_once('external.php'); before the function, how can I use the $lang array variables in my function without having to write "global" before each use?
Maybe passing it as an argument?
<?php
include 'external.php';
function chewbacca($lang_array){
echo $lang_array[1];
//...
}
Edit:
You could do the following too:
On external.php:
<?php
return array(
'foo',
'foobar',
'bar',
);
On index.php:
<?php
function chewbacca($lang_array){
echo $lang_array[1];
//...
}
$foo = include 'external.php';
chewbacca($foo);
Edit2:
Of course now you can use include_once, but I would recommend require_once because you won't have the array if the include fails and the script should stop with an error.
Unless I'm misunderstanding what you're after, you don't need to write global before each use, you just have to use it at the start of the function.
include('external.php');
chewbacca() {
global $lang;
echo $lang[1];
...
}
Simply said, you can't...
You have several ways to do this:
Way #1
global $lang;
include('external.php')
function chewbacca(){
global $lang;
echo $lang[1];
}
Way #2
function chewbacca(){
include('external.php')
echo $lang[1];
}
Way #3
function chewbacca(){
static $lang;
if(!is_array($lang)){ include('external.php'); }
echo $lang[1];
}
Way #4
include('external.php')
function chewbacca($lang){
echo $lang[1];
}
chewbacca($lang);
Good luck
PS: Another way would be to use a CLASS a load the strings in the class when it gets created (inside the constructor) and access the language strings from $this->lang...
Static class also is a solution.
class AppConfiguration {
static $languages = array(
'en' => 'English'
);
}
function functionName($param) {
$lang = AppConfiguration::$languages;
}
require_once that class in document and that's it.
If I understood you correctly, try and pass it to a local scope before using it; that way you'll only need to use the global scope once inside the function.
i have alias to include() in my functions.php file:
function render_template($template)
{
include($template);
}
and simple template.html :
Hello, <?php echo $name ?>
But unfortunately, alias function gave me this output:
require 'functions.php';
$name = "world";
include('template.html'); // Hello, world
render_template('template.html'); // PHP Notice:Undefined variable: name
why is that? and how i can fix this?
thanks.
You have two more options to make it work around the scope issue. (Using global would require localising a long list of vars. Also it's not actually clear if your $name resides in the global scope anyway and always.)
First you could just turn your render_template() function into a name-resolver:
function template($t) {
return $t; // maybe add a directory later on
}
Using it like this:
$name = "world";
include(template('template.html'));
Which is nicer to read and has obvious syntactical meaning.
The more quirky alternative is capturing the local variables for render_template:
$name = "world";
render_template('template.html', get_defined_vars());
Where render_template would require this addition:
function render_template($template, $vars)
{
extract($vars); // in lieu of global $var1,$var2,$var3,...
include($template);
}
So that's more cumbersome than using a name-resolver.
The variable $name is not visible at the point where include is called (inside function render_template). One way to fix it would be:
function render_template($template)
{
global $name;
include($template);
}
Its a Scope Problem, you can set the variable to global, or encapsulate the whole thing a little bit more, for example like that:
class view{
private $_data;
public function __construct(){
$this->_data = new stdClass();
}
public function __get($name){
return $this->_data->{$name};
}
public function __set($name,$value){
$this->_data->{$name} = $value;
}
public function render($template){
$data = $this->_data;
include($template);
}
}
$view = new view;
$view->name = "world";
$view->render('template.html');
template.html :
Hello <?php print $data->name; ?>
If $name is in the global scope then you can get around it by declaring the variable global with the function. But a better solution would be to re-architect the code to require passing the relevant variable value into the function.
This is expected.
Look here.
You would be interested in the following quote, "If the include occurs inside a function within the calling file, then all of the code contained in the called file will behave as though it had been defined inside that function. So, it will follow the variable scope of that function. An exception to this rule are magic constants which are evaluated by the parser before the include occurs".