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();
Related
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.
To ease up the debuging for my class(es) I want to bind a function to the status of other function events. The current set-up I have, is similair to following the code:
class config {
function __construct($file) {
$this->functions = array(); // The array with function run/succes information
if (!empty($file)) {
$this->checkFile($file);
}
}
public function checkFile($file) {
$this->functionStatus('run',true);
if (file_exists($file)) {
$this->functionStatus('succes',true);
return true;
} else {
$this->functionStatus('succes',true);
return false;
}
}
/* Simplified functionStatus function */
private function functionStatus($name,$value) {
/* - validations removed -*/
// Get parent function name
$callers = debug_backtrace();
$function = $callers[1]['function'];
/* - validations removed -*/
$this->functions[$function][$name] = $value;
}
}
An example of the principle in use:
$config = new config('example.ini');
print var_dump($config->functions);
/* Results in:
array(1) {
["checkFile"]=> array(2) {
["run"]=> bool(true)
["succes"]=> bool(true)
}
}
*/
While this set-up works fine. I would like to improve it by removing the manually placed $this->functionStatus('run',true) function everytime I create a function to keep the code a bit cleaner and prevent assuming a function isn't run because someone forgat defining the functionStatus at top of the function. Same goes for the definitions at the return events.
*Note, the best solution would also support this binding with other classes
Is there any way to accomplish this 'event binding' with PHP ?
You can do this using the __call magic method. Change all your public functios to private methods, and add a prefix to the name, e.g.
private function internal_checkFile($file) {
...
}
Then add the magic method:
public function __call($name, $arguments) {
$this->functionStatus('run', true);
return call_user_func_array(array($this, "internal_$name"), $arguments);
}
I've looked around a lot for help on this. I realise this is probably more to do with the way I am using objects (I'm new to OO PHP) but it's really bugging me. Here is a massively simplified version of what I'm trying to do:
<?php
class Show_message {
public $message_instance = ""; //ensure Message object variable is visible
function __construct() {
//do nothing
}
function display_message() {
$message_instance = new Message(); //instatiate Message object
echo $message_instance->message . " : in display_message function <br>"; //works
}
function display_again() {
echo $message_instance->message . " : in display_again function <br>"; //does not work
}
}
class Message {
public $message = ""; //ensure $this->message variable is visible?
function __construct() {
$this->message = "Hello world"; //make message
}
}
$instance = new Show_message(); //instatiate Show_message object
$instance->display_message(); //method to create instance and display message
$instance->display_again(); //method to display message again
?>
Why is the $message_instance->message not visible to the display_again() function?
You need to use $this->, otherwise you are storing the Message object locally to the function, not to the class instance.
$this->message_instance = new Message();
and $this->message_instance everywhere you are doing $message_instance.
Working Demo
Because you are setting a local variable inside the function, you must use $this to access object properties.
<?php
class Show_message {
public $message_instance = ""; //ensure Message object variable is visible
function __construct() {
$this->message_instance = new Message();
}
function display_message() {
//instatiate Message object
echo $this->message_instance->message . " : in display_message function <br>";
}
function display_again() {
echo $this->message_instance->message . " : in display_again function <br>";
}
}
class Message {
public $message = ""; //ensure $this->message variable is visible?
function __construct() {
$this->message = "Hello world"; //make message
}
}
$instance = new Show_message(); //instatiate Show_message object
$instance->display_message(); //method to create instance and display message
$instance->display_again(); //method to display message again
?>
I need to know do we have to check input parameters of class methods in PHP OOP or not?
For example imagine the method below:
public function show_message($message)
{
echo $message;
}
What is the best solution if programmer don't pass the message parameter to method? Let PHP to show it's warning or run time error or do something else ?
The "best" solution depends on what you want the method to do exactly, but generally, I'd suggest a combination of type-hinting and default values:
class Foo
{
public function doSomething ($message = 'None')
{
echo $message;
}
public function somethingElse (array $foo = array())
{
echo '<pre>';
print_r($foo);
echo '</pre>';//will always be an array
}
public function onlyMyself (Foo $instance)
{
return $instance->doSomething('I know this method exists');
}
public function myselfOrNothing(Foo $instance = null)
{
if ($instance === null)
{
return $this->doSomething('No instance provided');
}
return $instance->doSomething('Instance provided to '.__METHOD__);
}
}
$foo = new Foo;
$bar = new Bar;
$foo->onlyMyself($bar);//works fine
$foo->onlyMyself(array());//fails
$bar->myselfOrNothing();//works
$bar->somethingElse();//ok...
etcetera, you get the basic principle.
Note that, if you're using an abstract parent class (or just any old parent class), type-hinting a parent allows for the child to be passed, too:
class Bar extends Foo
{
}
class Foobar extends Bar
{
}
$fb = new Foobar;
$b = new Bar;
public function someClass(Foo $instance)
{//accepts instances of Foo, Bar and Foobar...
echo get_class($instance);//can echo any class name
}
Allow for a default value, then trap for that default. This puts control of what you do in your hands rather than the simple default PHP behaviour
public function show_message($message = "\x00")
{
if ($message === "\x00") {
// decide how critical this argument actually is, and react appropriately
throw new BadMethodCallException("The message argument is critical and must be passed to this method");
// or simply apply a default if it isn't critical
$message = 'Hello World';
}
echo $message;
}
I think the type of error should depend on how important the function is and if that is enough of a reason to stop execution if the parameter is not there.
if you are talking about input parameters validation. you can do something like this.
public function show_message($message = '') {
$result = 'No message';
if (!empty($message)) {
if (is_bool($message)) {
$result = 'It is a boolean';
}
if (is_int($message)) {
$result = 'It is a integer';
}
if (is_float($message)) {
$result = 'It is a float';
}
if (is_string($message)) {
$result = 'It is a string';
}
if (is_array($message)) {
$result = 'It is an array';
}
if (is_object($message)) {
$result = 'It is an object';
}
}
return $result;
}
I'm trying to add methods dynamically from external files.
Right now I have __call method in my class so when i call the method I want, __call includes it for me; the problem is I want to call loaded function by using my class, and I don't want loaded function outside of the class;
Class myClass
{
function__call($name, $args)
{
require_once($name.".php");
}
}
echoA.php:
function echoA()
{
echo("A");
}
then i want to use it like:
$myClass = new myClass();
$myClass->echoA();
Any advice will be appreciated.
Is this what you need?
$methodOne = function ()
{
echo "I am doing one.".PHP_EOL;
};
$methodTwo = function ()
{
echo "I am doing two.".PHP_EOL;
};
class Composite
{
function addMethod($name, $method)
{
$this->{$name} = $method;
}
public function __call($name, $arguments)
{
return call_user_func($this->{$name}, $arguments);
}
}
$one = new Composite();
$one -> addMethod("method1", $methodOne);
$one -> method1();
$one -> addMethod("method2", $methodTwo);
$one -> method2();
You cannot dynamically add methods to a class at runtime, period.*
PHP simply isn't a very duck-punchable language.
* Without ugly hacks.
You can dynamically add attributes and methods providing it is done through the constructor in the same way you can pass a function as argument of another function.
class Example {
function __construct($f)
{
$this->action=$f;
}
}
function fun() {
echo "hello\n";
}
$ex1 = new class('fun');
You can not call directlry $ex1->action(), it must be assigned to a variable and then you can call this variable like a function.
if i read the manual right,
the __call get called insted of the function, if the function dosn't exist
so you probely need to call it after you created it
Class myClass
{
function __call($name, $args)
{
require_once($name.".php");
$this->$name($args);
}
}
You can create an attribute in your class : methods=[]
and use create_function for create lambda function.
Stock it in the methods attribute, at index of the name of method you want.
use :
function __call($method, $arguments)
{
if(method_exists($this, $method))
$this->$method($arguments);
else
$this->methods[$method]($arguments);
}
to find and call good method.
What you are referring to is called Overloading. Read all about it in the PHP Manual
/**
* #method Talk hello(string $name)
* #method Talk goodbye(string $name)
*/
class Talk {
private $methods = [];
public function __construct(array $methods) {
$this->methods = $methods;
}
public function __call(string $method, array $arguments): Talk {
if ($func = $this->methods[$method] ?? false) {
$func(...$arguments);
return $this;
}
throw new \RuntimeException(sprintf('Missing %s method.'));
}
}
$howdy = new Talk([
'hello' => function(string $name) {
echo sprintf('Hello %s!%s', $name, PHP_EOL);
},
'goodbye' => function(string $name) {
echo sprintf('Goodbye %s!%s', $name, PHP_EOL);
},
]);
$howdy
->hello('Jim')
->goodbye('Joe');
https://3v4l.org/iIhph
You can do both adding methods and properties dynamically.
Properties:
class XXX
{
public function __construct($array1)
{
foreach ($array1 as $item) {
$this->$item = "PropValue for property : " . $item;
}
}
}
$a1 = array("prop1", "prop2", "prop3", "prop4");
$class1 = new XXX($a1);
echo $class1->prop1 . PHP_EOL;
echo $class1->prop2 . PHP_EOL;
echo $class1->prop3 . PHP_EOL;
echo $class1->prop4 . PHP_EOL;
Methods:
//using anounymous function
$method1 = function () {
echo "this can be in an include file and read inline." . PHP_EOL;
};
class class1
{
//build the new method from the constructor, not required to do it here by it is simpler.
public function __construct($functionName, $body)
{
$this->{$functionName} = $body;
}
public function __call($functionName, $arguments)
{
return call_user_func($this->{$functionName}, $arguments);
}
}
//pass the new method name and the refernce to the anounymous function
$myObjectWithNewMethod = new class1("method1", $method1);
$myObjectWithNewMethod->method1();
I've worked up the following code example and a helper method which works with __call which may prove useful. https://github.com/permanenttourist/helpers/tree/master/PHP/php_append_methods