Как выполнить public function action в php
Перейти к содержимому

Как выполнить public function action в php

  • автор:

Класс Input

Давайте теперь сделаем класс Input для работы с инпутами. Вот готовая реализация этого класса:

Давайте используем новый класс Input вместе с уже созданным нами классом Form :

setAttrs([‘action’ => », ‘method’ => ‘GET’]); echo $form->open(); echo (new Input)->setAttr(‘name’, ‘year’)->open(); echo (new Input)->setAttr(‘type’, ‘submit’)->open(); echo $form->close(); ?>

В результате получится следующая форма:

Скопируйте себе мой код класса Input . Скопируйте пример формы. Запустите его в браузере, убедитесь, что форма действительно появляется. Вбейте какие-нибудь данные в инпут и нажмите на кнопку отправки. Убедитесь, что форма действительно рабочая.

Убираем open

Давайте уберем метод open , добавив магию метода __toString :

public function __toString() < return parent::open(); >> ?>

Перепишите приведенный ниже код с учетом нашей правки:

setAttrs([‘action’ => », ‘method’ => ‘GET’]); echo $form->open(); echo (new Input)->setAttr(‘name’, ‘year’)->open(); echo (new Input)->setAttr(‘type’, ‘submit’)->open(); echo $form->close(); ?>

Некоторые замечания

Пока наш PHP код формы получается длиннее соответствующего HTML кода. Возникает вопрос: зачем нам PHP вариант, если все намного короче можно написать на HTML?

Все дело в том, что наша PHP реализация дает нам дополнительные возможности. Например, мы можем сделать так, чтобы данные из инпутов не исчезали после отправки формы.

И теперь преимущество в длине кода будет уже на стороне PHP варианта — длина HTML варианта существенно вырастет, а длина PHP варианта останется неизменной.

setAttrs([‘action’ => », ‘method’ => ‘GET’]); echo $form->open(); echo (new Input)->setAttr(‘name’, ‘year’); echo (new Input)->setAttr(‘type’, ‘submit’); echo $form->close(); ?>

Пусть у нас несколько инпутов:

setAttrs([‘action’ => », ‘method’ => ‘GET’]); echo $form->open(); echo (new Input)->setAttr(‘field1’, ‘year’); echo (new Input)->setAttr(‘field2’, ‘year’); echo (new Input)->setAttr(‘name’, ‘submit’); echo $form->close(); ?>

Как вы видите, длина инпутов PHP варианта теперь существенно короче.

Кроме того, HTML вариант имеет еще один существенный недостаток — для корректной работы имя инпута нужно повторить аж 3 раза: тут name=»field1″, тут isset($_REQUEST[‘field1’]) и тут echo $_REQUEST[‘field1’].

Представьте, каким кошмаром будет изменения имен нескольких инпутов. Это не говоря о возможность в одном из мест просто забыть изменить имя — и инпут будет работать некорректно.

В PHP варианте имя инпута задает в одном месте.

Убедившись в преимуществах нашего варианта формы, приступим к его реализации.

Реализация сохранения значений после отправки

Как вы должны знать, значение инпута задается в атрибуте value . Нам необходимо сделать следующее: если форма была отправлена, то в value инпута следует записать то значение, которое было в нем в момент отправки.

Каким образом получить это значение? Пусть имя инпута было year . В этом случае после отправки формы в $_REQUEST[‘year’] и будет находится нужное нам значение.

В нашем случае имя инпута хранится в родительском классе Tag в приватном свойстве $attrs . Наш класс Input как потомок класса Tag может получить доступ к любому атрибуту с помощью геттера, вот так: $inputName = $this->getAttr(‘name’).

Давайте получим имя нашего инпута, достанем значение из $_REQUEST по этому имени и запишем в value инпута:

// Переопределяем метод родителя: public function open() < $inputName = $this->getAttr(‘name’); // имя инпута $value = $_REQUEST[$inputName]; // получаем значение инпута по его имени $this->setAttr(‘value’, $value); // записываем в value инпута return parent::open(); // вызываем метод open родителя > public function __toString() < return $this->open(); // здесь теперь не метод родителя, а наш > > ?>

Приведенный выше код пока не очень корректный: он не учитывает того, что отправки формы могло еще и не быть. Давайте учтем:

// Переопределяем метод родителя: public function open() < $inputName = $this->getAttr(‘name’); // имя инпута // Если форма была отправлена и есть данные с именем нашего инпута: if (isset($_REQUEST[$inputName])) < $value = $_REQUEST[$inputName]; // получаем значение из $_REQUEST $this->setAttr(‘value’, $value); // записываем в value инпута > return parent::open(); // вызываем метод open родителя > public function __toString() < return $this->open(); > > ?>

Вот теперь наш код уже достаточно рабочий, но есть пару нюансов.

Что будет, если у нашего инпута по умолчанию уже есть какое-то значение (например, текущий год), например, вот так:

setAttr(‘name’, ‘year’) ->setAttr(‘value’, date(‘Y’)); // значение по умолчанию ?>

В этом случае в теории по заходу на страницу мы должны увидеть текущий год, но при желании можем его поменять, нажать на кнопку отправки — и после обновления страницы в инпуте будет тот год, который и был отправлен.

На самом деле наш код так и работает! Если была отправка формы, то мы попадем в условие и там изменим value инпута, но если отправки не было — value инпута останется таким, как и было задано.

Второй нюанс: есть инпуты, у которых нет атрибута name . Например, кнопка отправки формы. В этом случае с такими инпутами ничего и не надо делать. Учтем это дополнительным условием:

Ну вот теперь можно пробовать. Можете запустить приведенный ниже код формы, вбить что-то в инпут и нажать на кнопку отправки — после обновления страницы данные из инпута не исчезнут:

setAttrs([‘action’ => », ‘method’ => ‘GET’]); echo $form->open(); echo (new Input)->setAttr(‘name’, ‘year’); echo (new Input)->setAttr(‘type’, ‘submit’); echo $form->close(); ?>

А вот пример, когда в инпуте уже есть какое-то значение по умолчанию:

setAttrs([‘action’ => », ‘method’ => ‘GET’]); echo $form->open(); echo (new Input)->setAttr(‘name’, ‘year’)->setAttr(‘value’, date(‘Y’)); echo (new Input)->setAttr(‘type’, ‘submit’); echo $form->close(); ?>

Реализуйте самостоятельно сохранение значений инпутов после отправки. Проверьте работу данного механизма.

С помощью созданного класса сделайте форму с 5 -ю инпутами. Пусть в каждый инпут можно ввести число. Сделайте так, чтобы после отправки на экран выводилась сумма этих чисел, а введенные значения не пропадали из инпутов.

Как повесить выполнение метода на форму action html формы?

Роутинг — это маршрутизация: входящий URL разбирается специальным образом и по его результату выполняется определенный код (или как в вопросе метод класса). С роутингом напрямую связано понятие ЧПУ (человекопонятные урлы), которое позволяет исключить в адресах сложные параметры. Например вместо http://сайт/admin/new-page пришлось бы использовать http://сайт/admin.php?action=new-page

Примеры готовых систем маршрутизации:

  1. https://github.com/bramus/router
  2. https://github.com/nikic/FastRoute
  3. https://github.com/izniburak/php-router
  4. https://github.com/mrjgreen/phroute
  5. https://github.com/delight-im/PHP-Router

Отслеживать
ответ дан 17 дек 2019 в 11:52
1,935 1 1 золотой знак 8 8 серебряных знаков 20 20 бронзовых знаков

  • php
  • html
    Важное на Мете
Похожие

Подписаться на ленту

Лента вопроса

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.2.16.5008

Yii Framework

Привет всем! Создал модуль user (создал вообще то gii а не я).
Как можно сделать экшены не в контроллере а вынести в отдельные файлы?
Как это сделано в yupi.

flashimage Сообщения: 1517 Зарегистрирован: 2011.01.23, 12:43

Re: Создание Action в контроллере

Сообщение flashimage » 2013.04.21, 00:40

Бранчи это гомеоморфические эндофункторы, которые мапятся на субманифолды пространства Гилберта.
Bezlepkin Сообщения: 731 Зарегистрирован: 2012.11.10, 18:59 Контактная информация:

Re: Создание Action в контроллере

Сообщение Bezlepkin » 2013.04.21, 15:25

Делаю так:
Создал модуль user.
user
-controllers/
—DefaultController.php
—account/
—ShowAction.php
UserModule.php
views

setImport(array( 'user.models.*', 'user.components.*', )); > public function beforeControllerAction($controller, $action) < if(parent::beforeControllerAction($controller, $action)) < // this method is called before any module controller action is performed // you may place customized code here return true; >else return false; > > 

файл DefaultController.php

 'application.modules.user.controllers.account.ShowAction', ); > public function actionIndex() < echo 'Все хорошо!'; >> 

файл ShowAction.php

При вызове localhost/yii/user то actionIndex из дефолтного контроллера все работает
а при вызове localhost/yii/user/show ничего не работает, 404

Как выполнить public function action в php

Создание копии объекта с абсолютно идентичными свойствами не всегда является приемлемым вариантом. Хорошим примером необходимости копирования конструкторов может послужить ситуация, когда у вас есть объект, представляющий собой окно GTK и содержащий ресурс-идентификатор этого окна; когда вы создаёте копию этого объекта, вам может понадобиться, чтобы копия объекта содержала ресурс-идентификатор нового окна. Другим примером может послужить ситуация, когда ваш объект содержит ссылку на какой-либо другой используемый объект и, когда вы создаёте копию родительского объекта, вам нужно также создать новый экземпляр этого другого объекта, так, чтобы копия объекта-контейнера содержала собственный отдельный экземпляр содержащегося объекта.

Копия объекта создаётся с использованием ключевого слова clone (который вызывает метод __clone() объекта, если это возможно).

$copy_of_object = clone $object;

При клонировании объекта, PHP выполняет поверхностную копию всех свойств объекта. Любые свойства, являющиеся ссылками на другие переменные, останутся ссылками.

__clone (): void void

После завершения клонирования, если метод __clone() определён, то будет вызван метод __clone() вновь созданного объекта для возможного изменения всех необходимых свойств.

Пример #1 Клонирование объекта

class SubObject
static $instances = 0 ;
public $instance ;

public function __construct () $this -> instance = ++ self :: $instances ;
>

public function __clone () $this -> instance = ++ self :: $instances ;
>
>

class MyCloneable
public $object1 ;
public $object2 ;

function __clone ()
// Принудительно клонируем this->object1, иначе
// он будет указывать на один и тот же объект.
$this -> object1 = clone $this -> object1 ;
>
>

$obj = new MyCloneable ();

$obj -> object1 = new SubObject ();
$obj -> object2 = new SubObject ();

$obj2 = clone $obj ;

print «Оригинальный объект:\n» ;
print_r ( $obj );

print «Клонированный объект:\n» ;
print_r ( $obj2 );

Результат выполнения приведённого примера:

Оригинальный объект: MyCloneable Object ( [object1] => SubObject Object ( [instance] => 1 ) [object2] => SubObject Object ( [instance] => 2 ) ) Клонированный объект: MyCloneable Object ( [object1] => SubObject Object ( [instance] => 3 ) [object2] => SubObject Object ( [instance] => 2 ) )

Возможно обращаться к свойствам/методам только что склонированного объекта:

Пример #2 Доступ к только что склонированному объекту

$dateTime = new DateTime ();
echo (clone $dateTime )-> format ( ‘Y’ );
?>

Вывод приведённого примера будет похож на:

2016

User Contributed Notes 14 notes

18 years ago

I think it’s relevant to note that __clone is NOT an override. As the example shows, the normal cloning process always occurs, and it’s the responsibility of the __clone method to «mend» any «wrong» action performed by it.

13 years ago

Here is test script i wrote to test the behaviour of clone when i have arrays with primitive values in my class — as an additonal test of the note below by jeffrey at whinger dot nl

private $myArray = array();
function pushSomethingToArray ( $var ) array_push ( $this -> myArray , $var );
>
function getArray () return $this -> myArray ;
>

//push some values to the myArray of Mainclass
$myObj = new MyClass ();
$myObj -> pushSomethingToArray ( ‘blue’ );
$myObj -> pushSomethingToArray ( ‘orange’ );
$myObjClone = clone $myObj ;
$myObj -> pushSomethingToArray ( ‘pink’ );

//testing
print_r ( $myObj -> getArray ()); //Array([0] => blue,[1] => orange,[2] => pink)
print_r ( $myObjClone -> getArray ()); //Array([0] => blue,[1] => orange)
//so array cloned

17 years ago

I ran into the same problem of an array of objects inside of an object that I wanted to clone all pointing to the same objects. However, I agreed that serializing the data was not the answer. It was relatively simple, really:

Note, that I was working with a multi-dimensional array and I was not using the Key=>Value pair system, but basically, the point is that if you use foreach, you need to specify that the copied data is to be accessed by reference.

13 years ago

Another gotcha I encountered: like __construct and __desctruct, you must call parent::__clone() yourself from inside a child’s __clone() function. The manual kind of got me on the wrong foot here: «An object’s __clone() method cannot be called directly.»

14 years ago

Here are some cloning and reference gotchas we came up against at Last.fm.

1. PHP treats variables as either ‘values types’ or ‘reference types’, where the difference is supposed to be transparent. Object cloning is one of the few times when it can make a big difference. I know of no programmatic way to tell if a variable is intrinsically a value or reference type. There IS however a non-programmatic ways to tell if an object property is value or reference type:

$a = new A ;
$a -> p = ‘Hello’ ; // $a->p is a value type
var_dump ( $a );

$ref =& $a -> p ; // note that this CONVERTS $a->p into a reference type!!
var_dump ( $a );

?>

2. unsetting all-but-one of the references will convert the remaining reference back into a value. Continuing from the previous example:

unset( $ref );
var_dump ( $a );

?>

I interpret this as the reference-count jumping from 2 straight to 0. However.

2. It IS possible to create a reference with a reference count of 1 — i.e. to convert an property from value type to reference type, without any extra references. All you have to do is declare that it refers to itself. This is HIGHLY idiosyncratic, but nevertheless it works. This leads to the observation that although the manual states that ‘Any properties that are references to other variables, will remain references,’ this is not strictly true. Any variables that are references, even to *themselves* (not necessarily to other variables), will be copied by reference rather than by value.

Here’s an example to demonstrate:

class ByRef
var $prop ;
function __construct () < $this ->prop =& $this -> prop ; >
>

$a = new ByVal ;
$a -> prop = 1 ;
$b = clone $a ;
$b -> prop = 2 ; // $a->prop remains at 1

$a = new ByRef ;
$a -> prop = 1 ;
$b = clone $a ;
$b -> prop = 2 ; // $a->prop is now 2

4 years ago

Here is a basic example about clone issue. If we use clone in getClassB method. Return value will be same as new B() result. But it we dont use clone we can effect B::$varA.

class A
protected $classB;

public function __construct() $this->classB = new B();
>

public function getClassB()
return clone $this->classB;
>
>

class B
protected $varA = 2;

public function getVarA()
return $this->varA;
>

public function setVarA()
$this->varA = 3;
>
>

echo $a->getClassB()->getVarA() . PHP_EOL;// with clone -> 2, without clone it returns -> 3

echo $classB->getVarA() . PHP_EOL; // returns always 3

16 years ago

It should go without saying that if you have circular references, where a property of object A refers to object B while a property of B refers to A (or more indirect loops than that), then you’ll be glad that clone does NOT automatically make a deep copy!

class Foo
var $that ;

function __clone ()
$this -> that = clone $this -> that ;
>

$a = new Foo ;
$b = new Foo ;
$a -> that = $b ;
$b -> that = $a ;

$c = clone $a ;
echo ‘What happened?’ ;
var_dump ( $c );

9 years ago

This base class automatically clones attributes of type object or array values of type object recursively. Just inherit your own classes from this base class.

class clone_base
public function __clone ()
$object_vars = get_object_vars ( $this );

foreach ( $object_vars as $attr_name => $attr_value )
if ( is_object ( $this -> $attr_name ))
$this -> $attr_name = clone $this -> $attr_name ;
>
else if ( is_array ( $this -> $attr_name ))
// Note: This copies only one dimension arrays
foreach ( $this -> $attr_name as & $attr_array_value )
if ( is_object ( $attr_array_value ))
$attr_array_value = clone $attr_array_value ;
>
unset( $attr_array_value );
>
>
>
>
>
?>

Example:
class foo extends clone_base
public $attr = «Hello» ;
public $b = null ;
public $attr2 = array();

public function __construct ()
$this -> b = new bar ( «World» );
$this -> attr2 [] = new bar ( «What’s» );
$this -> attr2 [] = new bar ( «up?» );
>
>

class bar extends clone_base
public $attr ;

public function __construct ( $attr_value )
$this -> attr = $attr_value ;
>
>

echo «» ;

$f1 = new foo ();
$f2 = clone $f1 ;
$f2 -> attr = «James» ;
$f2 -> b -> attr = «Bond» ;
$f2 -> attr2 [ 0 ]-> attr = «Agent» ;
$f2 -> attr2 [ 1 ]-> attr = «007» ;

echo «f1.attr keyword»>. $f1 -> attr . «\n» ;
echo «f1.b.attr keyword»>. $f1 -> b -> attr . «\n» ;
echo «f1.attr2[0] keyword»>. $f1 -> attr2 [ 0 ]-> attr . «\n» ;
echo «f1.attr2[1] keyword»>. $f1 -> attr2 [ 1 ]-> attr . «\n» ;
echo «\n» ;
echo «f2.attr keyword»>. $f2 -> attr . «\n» ;
echo «f2.b.attr keyword»>. $f2 -> b -> attr . «\n» ;
echo «f2.attr2[0] keyword»>. $f2 -> attr2 [ 0 ]-> attr . «\n» ;
echo «f2.attr2[1] keyword»>. $f2 -> attr2 [ 1 ]-> attr . «\n» ;
?>

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *