So i am new to oo php and i-m building a sample app for learning purpses , one thing i must do is load a language file according to some settings
The code, as you will discover below is divided between two classes , a settings class witch should load the language file and another class in this case "contact" witch should read the array in the language files and display the propper message.
this is the Settings class
the lang variable sets the default language it can take 2 values at the moment : ro- for romanian and en - for english ,
class Settings
{
static public $lang = 'ro';
static public $load;
static public function get_language()
{
if(self::$lang == 'ro')
{
self::$load = require 'ro.php';
}
elseif(self::$lang == 'en')
{
self::$load = require 'en.php';
}
return self::$load;
}
}
The second class :
class Contact extends Settings {
//proprietati
public $nume;
public $subiect;
public $mesaj;
public $dincs;
//comportament - metode
public function __construct()
{
//$this->dincs = 'Din construct';
parent::get_language();
}
public function write_file()
{
if(empty($this->nume))
{
return $mess['name_error'];
}
else
{
$fp = fopen('data.txt', 'w');
fwrite($fp, $this->nume.".".$this->subiect .".". $this->mesaj."|".$this->dincs ."|".parent::$load);
fclose($fp);
return $mess['file_written'];
}
}
}
A sample from the language file:
$mess = array ("name_error" => "You must insert your name",
"file_written" => "the file has been written",
);
I have looked up on google , and tried some other stuff and can't seem to get it to work , and that may be because i am approaching this problem incorectly.
Plese help.
`
class Settings
{
protected $language = 'ro';
protected $load;
public function setLanguage($language = 'ro')
{
$this->language = $language;
// file_get_contents()
$this->load = require($this->language . '.php');
}
public function getLanguage()
{
return $this->language;
}
}
class Contact extends Settings
{
protected $name;
protected $subject;
protected $message;
protected $dincs;
protected $settingsObject;
// set all the properties below...
public function setName($name)
{
$this->name = $name;
}
public function setSubject($subject)
{
$this->subject = $subject;
}
public function setMessage($message)
{
$this->message = $message;
}
public function setDincs($dincs)
{
$this->dincs = $dincs;
}
// get all the properties...
public function getName()
{
return $this->name;
}
// This function only accepts an instance of Settings as the parameter
public function setSettingsObject(Settings $settings)
{
$this->settingsObject = $settings;
}
public function writeContentsToFile()
{
// if there is nothing in name, throw a new exception
if (empty($this->name))
{
throw new Exception('name has not been set! Set name before calling '. __METHOD__);
}
else
{
// get the file
$fp = fopen('data.txt', 'w');
// formatted string
$contents = sprintf('%s . %s . %s | %s | %s', $this->name, $this->subject, $this->message, $this->dincs, $this->settingsObject->getLanguage());
// write to the file
fwrite($fp, $contents);
// close the handler
fclose($fp);
return ('File written! Contents written: ' . $contents);
}
}
}
// instantiate settings
$settings = new Settings();
$settings->setLanguage('en');
// instantiate contact and set the settings object
$contact = new Contact();
$contact->setName('Joe Smith'); // if this is not set, ::writeContentsToFile will throw an Exception
$contact->setSettingsObject($settings);
// try and catch the Exception that ::writeContentsToFile may throw
try
{
echo $contact->writeContentsToFile();
}
catch (Exception $exception)
{
var_dump($exception);
}
?>
`
self::$load = require 'en.php';
You assign here a return value from the file inclusion to self::$load; not the variable $mess you defined in your language file.
So, there are two ways now: return the array $mess (return $mess;) from the language file.
Or you can just write:
require 'en.php';
self::$load = $mess;
Little side note: I'd check in your Settings::getLanguage() method if (self::$load) and return then the self::$load variable instead of refetching the language fileā¦)
Related
The following code is my template engine and it works great, with the small exception when a tpl file is not found the page should echo the error message "Error! Can't load the template file $templateFile".
namespace Template;
class Template
{
private $tags = [];
private $template;
public function __construct($templateFile)
{
$this->template = $this->getFile($templateFile);
if (!$this->template) {
return "Error! Can't load the template file $templateFile";
}
}
public function render()
{
$this->replaceTags();
echo $this->template;
}
public function set($tag, $value)
{
$this->tags[$tag] = $value;
}
public function getFile($file)
{
if (file_exists($file)) {
$file = file_get_contents($file);
return $file;
} else {
return false;
}
}
private function replaceTags()
{
foreach ($this->tags as $tag => $value) {
$this->template = str_replace('{'.$tag.'}', $value, $this->template);
}
return true;
}
}
I expect, when a matching .tpl file is not found the page should display "Error! Can't load the template file $templateFile", the actual output is a blank page.
Constructors are void function, Viod function means that can not return anything so you can't use return statement in constructor.
Instead of passing parameter in a constructor, Make a function for it and use return statement in that function
public function checkFile($filename)
{
$this->template = $this->getFile($filename);
if (!$this->template) {
return "Error! Can't load the template file $filename";
}
return true;
}
Make an Object of class and call that function
$obj = new Template;
$filexists = $obj->checkFile($filename);
if(!$filexists){
echo $filexists;
}
I am trying to display an array of messages at the end of my PHP class. My message handler is working, but only if I "add_message" from within the main parent class and not if I call this function from within a child class. Sorry if this is vague but was not sure how to word the question.
TLDR; How can I add a message from within class Example?
MAIN PARENT CLASS
class Init {
public function __construct() {
$this->load_dependencies();
$this->add_messages();
$this->add_msg_from_instance();
}
private function load_dependencies() {
require_once ROOT . 'classes/class-messages.php';
require_once ROOT . 'classes/class-example.php';
}
public function add_messages() {
$this->messages = new Message_Handler();
$this->messages->add_message( 'hello world' );
}
// I Would like to add a message from within this instance....
public function add_msg_from_instance() {
$example = new Example();
$example->fire_instance();
}
public function run() {
$this->messages->display_messages();
}
}
MESSAGE HANDLER
class Message_Handler {
public function __construct() {
$this->messages = array();
}
public function add_message( $msg ) {
$this->messages = $this->add( $this->messages, $msg );
}
private function add( $messages, $msg ) {
$messages[] = $msg;
return $messages;
}
// Final Function - Should display array of all messages
public function display_messages() {
var_dump( $this->messages );
}
}
EXAMPLE CLASS
class Example {
public function fire_instance() {
$this->messages = new Message_Handler();
$this->messages->add_message( 'Hello Universe!' ); // This message is NOT being displayed...
}
}
Because you want to keep the messages around different object, you should pass the object or use a static variable.
I would use a static variable like so:
class Init {
public function __construct() {
$this->load_dependencies();
$this->add_messages();
$this->add_msg_from_instance();
}
private function load_dependencies() {
require_once ROOT . 'classes/class-messages.php';
require_once ROOT . 'classes/class-example.php';
}
public function add_messages() {
// renamed the message handler variable for clarity
$this->message_handler = new Message_Handler();
$this->message_handler->add_message( 'hello world' );
}
// I Would like to add a message from within this instance....
public function add_msg_from_instance() {
$example = new Example();
$example->fire_instance();
}
public function run() {
$this->message_handler->display_messages();
}
}
class Message_Handler {
// use a static var to remember the messages over all objects
public static $_messages = array();
// add message to static
public function add_message( $msg ) {
self::$_messages[] = $msg;
}
// Final Function - Should display array of all messages
public function display_messages() {
var_dump( self::$_messages );
}
}
class Example {
public function fire_instance() {
// new object, same static array
$message_handler = new Message_Handler();
$message_handler->add_message( 'Hello Universe!' );
}
}
// testing...
new Init();
new Init();
$init = new Init();
$init->add_msg_from_instance();
$init->add_msg_from_instance();
$init->add_msg_from_instance();
$init->run();
Although global variables might not be the best design decision, you have at least two approaches to achieve what you want:
Use singleton.
Nowadays it is considered anti-pattern, but it is the simplest way: make message handler a singleton:
class MessageHandler
{
private static $instance;
private $messages = [];
public static function instance(): self
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct()
{
}
public function addMessage($message): self
{
$this->messages[] = $message;
return $this;
}
public function messages(): array
{
return $this->messages;
}
}
Then instead of creating a new instance of MessageHandler access it via the static method MessageHandler::instance(). Here is a demo.
Use DI container to inject the same instance (that is created once and held in the container) into all instances that need to access it. This approach is more preferable, but harder to implement in the project where there is no DI container available in the first place.
I want to modify this code:
function send($message, $mode, $param1, $param2)
{
$msg = ">> " . $message;
if ($mode == "client") {
$client = $param1; // $param1 is a websocket source variable
// code
}
elseif ($mode == "clients") {
$clients = $param1; // now $param1 is an array of websocket sources
// code
}
elseif ($mode == "all") {
// code
}
}
send("Hello World!", "all", $whatever1, $whatever2);
(this function actually reads $mode to understand what it is going to do)
to the code below.
This code WILL NOT work. I would you like to tell me what changes i have to do for it to work
class send($message)
{
$msg = ">> " . $message;
public function client($client, $param2) { // $client is $param1 of previous code
// code using $msg
}
public function clients($clients, $param2) { // $clients is an array and the $param1 of previous code
// code using $msg
}
public function all($param2) {
// code using $msg
}
}
send("Hello World!")::all($whatever2);
I know the second code is very messed up. It doesn't work, but I want to do something like this. To categorize functions and parameters. I hope you got the idea. Maybe there is no such way and I have to use the $mode method in the first code?
You are trying to decompose the function and create a class from the parts.
There are some syntax errors in your code.
You are mixing up a lot of concepts here: functions, classes, static and dynamic calls. Please read the basic chapters in the PHP manual about OOP: http://php.net/manual/en/language.oop5.php
This part is wrong.
class send($message)
{
A class definition begins with the keyword class, followed by a class name:
class Send {
}
You can not use this directly inside a class, you could wrap it in the constructor or in a function.
$msg = ">> " . $message;
You can declare a constructor which accepts a parameter:
public function __construct($message) {
$this->message = $message;
}
class Send
{
private $message = '';
public function __construct($message) {
$this->message = $message;
}
public function toClient($client, $param) {
var_dump($this->message, $client, $param);
}
public function toClients($clients, $param) {
var_dump($this->message, $clients, $param);
}
public function toAll($param) {
var_dump($this->message, $param);
}
}
This class accept the message in the constructor and sets it as a property.
You might then reuse it across the functions ($this->message).
// Usage
$message = 'Hello World';
// instantiate the class
// and pass the message you want to send as param
// execute a specific class method
$send = new Send($message);
$send->toClient('john', 'more');
// with PHP 5.4 it's a one-liner
(new Send($message))->toClient('john', 'more');
I figured it out, many many thanks to Jens A. Koch
For all of you out there:
Prior to PHP 5.4:
class send {
public function __construct($msg) {
$this -> message = $msg;
}
public function clients(/* many params */) {
echo "some clients say: ".$this->message;
}
public function client(/* many params */) {
echo "one client says: ".$this->message;
}
public function all(/* many params */) {
echo "all clients say: ".$this->message;
}
// function b (build) returns the class
public function b($msg) {return new self($msg);}
}
// CALLING IT
send::b("test")->clients(); // >> some clients say: test
PHP 5.4+ (unfortunately I have 5.3 but it should work)
"public function b" is not needed:
class send {
public function __construct($msg) {
$this -> message = $msg;
}
public function clients(/* many params */) {
echo "some clients say: ".$this->message;
}
public function client(/* many params */) {
echo "one client says: ".$this->message;
}
public function all(/* many params */) {
echo "all clients say: ".$this->message;
}
}
// CALLING IT
(new send("test"))->clients();
Can anyone help me with php classes example. I have to make class "information" that has information about users: id, email, password, first name, last name, phone.
Also, class must have a method to print all the user data on the output.
It's really simple skeleton, because you didn't try anything, so just for you to have idea how it works...
class User
{
private $id;
private $email;
// ...
public function __construct($id, $email...)
{
$this->id = $id;
$this->email = $email;
// ...
}
public function printAll()
{
return $this->id . ' ' . $this->email;
}
}
I suggest you reading this: http://codular.com/introducing-php-classes and then come back with any questions.
Here is an example of a PHP class:
class DBIGenerator{
private $table;
private $name;
private $path;
public function __construct($table,$name='default_file.php',
$path='DEFAULTPATH/'){
$this->table=$table;
$this->name=$name;
$this->path=$path;
}
public function generate(){
// build class header
$str='<?php class '.$this->name.'{';
if(!$result=mysql_query('SHOW COLUMNS FROM '.$this->table)){
throw new Exception('Failed to run query');
}
// build data member declaration
if(mysql_num_rows($result)<1){
throw new Exception('Not available columns in table');
}
$methods='';
while($row=mysql_fetch_array($result,MYSQL_ASSOC)){
$str.='private $'.$row['Field'].'=\'\';';
$methods.='public function set'.$row['Field'].'($'.$row
['Field'].'){$this->'.$row['Field'].'=$'.$row
['Field'].';}';
$methods.='public function get'.$row['Field'].'(){return
$this->'.$row['Field'].';}';
// store field names in array
$fields[]=$row['Field'];
}
// build empty constructor
$str.='public function __construct(){}';
// build modifiers and accessors
$str.=$methods;
// build load() method
$str.='public function load(){$r=mysql_query("SELECT * FROM
'.$this->table.' WHERE id=\'$this->id\'");';
$str.='return mysql_fetch_array($r,MYSQL_ASSOC);}';
// build submit() method
$str.='public function submit(){mysql_query("INSERT INTO '.$this-
>table.' SET ';
foreach($fields as $field){
$str.=($field!='id')?$field.'=\'$this->'.$field.'\',':'';
}
$str.='");$this->id=mysql_insert_id();';
$str=preg_replace("/,\"/","\"",$str).'}';
// build update() method
$str.='public function update(){mysql_query("UPDATE '.$this-
>table.' SET ';
foreach($fields as $field){
$str.=($field!='id')?$field.'=\'$this->'.$field.'\',':'';
}
$str=preg_replace("/,$/","",$str);
$str.=' WHERE id=\'$this->id\'");}';
// build delete() method
$str.='public function delete(){mysql_query("DELETE FROM '.
$this->table.' WHERE id=\'$this->id\'");}';
$str.='}?>';
// open or create class file
if(!$fp=fopen($this->path.$this->name.'.php','w')){
throw new Exception('Failed to create class file');
}
// lock class file
if(!flock($fp,LOCK_EX)){
throw new Exception('Unable to lock class file');
}
// write class code to file
if(!fwrite($fp,$str)){
throw new Exception('Error writing to class file');
}
flock($fp,LOCK_UN);
fclose($fp);
// delete temporary variables
unset($fp,$str,$row,$fields,$field,$methods);
}
public function getObject(){
// check if class file exists
if(!file_exists($this->path.$this->name.'.php')){
throw new Exception('Failed to include class file');
}
require_once($this->path.$this->name.'.php');
// create data access object
return new $this->name;
}
}
Read more at http://www.devshed.com/c/a/PHP/Building-ObjectOriented-Database-Interfaces-in-PHP-Updating-the-Application-to-PHP-5/1/#Czocu1kMhhuTvg2e.99
Take a look at the snippet below as a basic way to implementing as expressed:
<?php
class information
{
public $id = 1;
public $email = "mail#mail.com";
public $pw = "A2D7DFEA88AC88"; //Don't forget, PW are usually hashed ;)
public function id() {
echo $this->id;
}
public function email() {
echo $this->email;
}
public function pw() {
echo $this->pw;
}
}
$test = new information();
$test->id;
?>
I understand that one can use interfaces to mandate the definition of a function, but I cannot find something that enables one to mandate function calls, such that e.g. if I create a class being a member of another class (via extends, etc), with a function, for that class to automatically ensure that mandatory functions are called in part with that function.
I mean, to clarify further:
class domain {
function isEmpty($input) {
//apply conditional logic and results
}
}
class test extends domain {
function addTestToDBTable($test) {
/**
* try to add but this class automatically makes it so that all rules of
* class domain must be passed before it can run
* - so essentially, I am no longer required to call those tests for each and
* every method
**/
}
}
Apologies if this appears incoherent by any means. Sure, it seems lazy but I want to be able to force context without having to concern abou
Update:
Okay, to clarify further: in PHP, if I extend and declare a __construct() for a child class, that child class will override the parent __construct(). I do not want this, I want the parent construct to remain and mandate whatever as it pleases just as the child class may do so also.
I guess it can be done in two different ways.
Aspect Oriented Programming
Have a look here https://github.com/AOP-PHP/AOP
Generate or write Proxy classes
A really simple example could be:
<?php
class A {
public function callMe() {
echo __METHOD__ . "\n";
}
}
class B extends A {
// prevents instantiation
public function __construct() {
}
public function shouldCallMe() {
echo __METHOD__ . "\n";
}
public static function newInstance() {
return new ABProxy();
}
}
class ABProxy {
private $b;
public function __construct() {
$this->b = new B();
}
public function __call($method, $args) {
$this->b->callMe();
return call_user_func_array(array($this->b, $method), $args);
}
}
// make the call
$b = B::newInstance();
$b->shouldCallMe();
// Outputs
// ------------------
// A::callMe
// B::shouldCallMe
Hopes this helps a bit.
Sounds like you want a Decorator.
See This answer for a detailed explanation on how to do it. Note that it does not require a class extension.
I would use a domain-validating decorator with some doc-block metaprogramming magic. But this is really a job for an entire library, which no doubt exists.
fiddle
<?php
class FooDomain {
public static function is_not_empty($input) {
return !empty($input);
}
}
class Foo {
/**
* #domain FooDomain::is_not_empty my_string
*/
public function print_string($my_string) {
echo $my_string . PHP_EOL;
}
}
$foo = new DomainValidator(new Foo());
$foo->print_string('Hello, world!');
try {
$foo->print_string(''); // throws a DomainException
} catch (\DomainException $e) {
echo 'Could not print an empty string...' . PHP_EOL;
}
// ---
class DomainValidator {
const DOMAIN_TAG = '#domain';
private $object;
public function __construct($object) {
$this->object = $object;
}
public function __call($function, $arguments) {
if (!$this->verify_domain($function, $arguments)) {
throw new \DomainException('Bad domain!');
}
return call_user_func_array(
array($this->object, $function),
$arguments
);
}
public function __get($name) {
return $this->object->name;
}
public function __set($name, $value) {
$this->object->name = $value;
}
private function verify_domain($function, $arguments) {
// Get reference to method
$method = new \ReflectionMethod($this->object, $function);
$domains = $this->get_domains($method->getDocComment());
$arguments = $this->parse_arguments(
$method->getParameters(),
$arguments
);
foreach ($domains as $domain) {
if (!call_user_func(
$domain['name'],
$arguments[$domain['parameter']]
)) {
return false;
}
}
return true;
}
private function get_domains($doc_block) {
$lines = explode("\n", $doc_block);
$domains = array();
$domain_tag = DomainValidator::DOMAIN_TAG . ' ';
foreach ($lines as $line) {
$has_domain = stristr($line, $domain_tag) !== false;
if ($has_domain) {
$domain_info = explode($domain_tag, $line);
$domain_info = explode(' ', $domain_info[1]);
$domains[] = array(
'name' => $domain_info[0],
'parameter' => $domain_info[1],
);
}
}
return $domains;
}
private function parse_arguments($parameters, $values) {
$ret = array();
for ($i = 0, $size = sizeof($values); $i < $size; $i++) {
$ret[$parameters[$i]->name] = $values[$i];
}
return $ret;
}
}
Output:
Hello, world!
Could not print an empty string...