powered by simpleCommunicator - 2.0.36     © 2025 Programmizd 02
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / PHP - вопросы по ссылкам
23 сообщений из 23, страница 1 из 1
PHP - вопросы по ссылкам
    #39875720
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не получается у меня решить несколько вопросов.
Не подскажите решение? Если это зависит от версии, то мне актуальна версия 5.4.

1. Допустим мне нужна функция, которая может принимать как byref, так и byval аргументы. То есть эту функцию я могу вызывать как func1($arr), так и func1([]) — в первом варианте в $arr после вызова функции могут быть внесены изменения.
Я не могу в ее декларации написать function func1(&$arg), потому что тогда второй синтаксис станет недоступен.
Если же использовать декларацию function func1($arg), то по всей видимости добраться до ссылки на $arg будет невозможно.
В интернете я нагуглил такой пример (способы с перехватом вывода и парсингом debug_zval_dump я вообще не рассматриваю):
Код: php
1.
2.
3.
4.
5.
6.
7.
function isReference($variable) {
    $variable = array($variable);
    $arg = func_get_arg(0);
    $isRef = isset($arg[0]) && $arg === array($variable[0]);
    $variable = $variable[0];
    return $isRef;
}


Однако я не пойму, как этот код работает (если он вообще работает), такая проверка:
Код: php
1.
2.
3.
4.
5.
$p = '123';
$r = &$p;
var_dump(isReference($p));
var_dump(isReference($r));
var_dump(isReference([]));


дает false для всех трех примеров.

2. Допустим у меня есть функция с произвольным числом аргументов. И в один из аргументов я хочу возвращать значения, если это потребуется. Внутри этой функции я использую func_get_args, то в этом случае до ссылок я добраться не могу.
Тут я придумал два способа, но первый способ начиная с 5.4 не работает (да и в любом случае такой способ мне не нравится), а второй способ имеет те же ограничения, что и первый вопрос (я не могу вызвать эту функцию и передать не ссылку):
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
$p = [':a'=>111, ':b'=>22];

function func1()
{
        $args = debug_backtrace(false,0)[0]['args'];
        foreach($args as &$arg) $arg['test1'] = 'func1';
}

function func2(&$arg1=null,&$arg2=null,&$arg3=null,&$arg4=null)
{
        $arg1['test2'] = 'func2';
}

func1(?$p);
func2($p);
func2([]);
var_dump($p);
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39875742
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сочинил такой способ, максимально близкий к тому, что мне бы хотелось (за исключением дуального byval/byref аргумента функции, похоже это ограничение архитектуры):
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
class DBEngine
{
        private $param = [];
        private $bind;
        function param($param=null, &$value=null)
        {
                $argn = func_num_args();
                if (!$argn) return $this->param;
                if (!isset($param)) return $this->param = [];
                if ($argn > 1) $this->param[$param] = &$value;
                if (!array_key_exists($param, $this->param)) return null;
                return $this->param[$param];
        }
        function query($sql, &$params=null, $options=null)
        {
                $this->param(null);
                if (isset($params)) foreach ($params as $key=>&$val) $this->param($key, $val);
                $this->proc();
                $this->exec();
                $tmp = $this->param(); foreach ($tmp as $key=>&$val) $params[$key] = &$val;
        }
        function proc()
        {
                $params = &$this->param;
                $this->bind(':a', $params[':a']);
                $this->bind(':c', $params[':c']);
        }
        function bind($label, &$var)
        {
                $this->bind[$label] = &$var;
        }
        function exec()
        {
                $ref = &$this->bind[':a']; $ref = 123;
                $ref = &$this->bind[':c']; $ref = 321;
        }
}

$db = new DBEngine();

$p = [':a'=>111, ':b'=>222];
$db->query(null, $p);
print_r($p);


Здесь методы bind и exec эмулируют методы внешней библиотеки oci8, а разбивка на методы query и proc обусловлена уже моими предпочтениями.
К внутреннему свойству params в методе proc я вынужден обращаться напрямую ($params = &$this->param;), потому что если получать его через функцию ($params = $this->param();), то я получаю не ссылку, а копию, и соответственно к методу bind я привязываю не исходные переменные, а копии. Из-за этого в реальном коде это свойство я вынужден делать protected, а не private.
Не посоветуете, что тут улучшить или переделать?
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39875772
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот финальный вариант:
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
function dbg($label, $var)
{
        print "$label  ##  ";
        ob_start();
        var_dump($var);
        $str = ob_get_contents();
        ob_end_clean();
        $str = preg_replace('/=>\n\s*/m', '=>', $str);
        print $str;
}

class ext
{
        private static $bind;
        static function bind($label, &$var)
        {
                self::$bind[$label] = &$var;
        }
        static function exec()
        {
                $ref = & self::$bind[':a']; $ref = 123;
                $ref = & self::$bind[':c']; $ref = 321;
        }
}

class DBEngine
{
        private $param = [];
        private function param($param=null, &$value=null)
        {
                $argn = func_num_args();
                if (!$argn) return $this->param;
                if (!isset($param)) return $this->param = [];
                if ($argn > 1) $this->param[$param] = &$value;
                if (!array_key_exists($param, $this->param)) return $tmp=null;
                return $this->param[$param];
        }
        public function query($sql, &$params=null, $options=null)
        {
                $this->param(null);
                if (isset($params)) foreach ($params as $key=>&$val) $this->param($key, $val);
                $this->proc();
                ext::exec();
                $tmp = $this->param(); foreach ($tmp as $key=>&$val) $params[$key] = &$val;
        }
        public function proc()
        {
                $params = &$this->param;
                ext::bind(':a', $params[':a']);
                ext::bind(':c', $params[':c']);
        }
}

// Проверка эмулятора для типового сценария
$v1 = 'abc';
$v2 = null;
dbg('before', ['v1'=>$v1, 'v2'=>$v2]);
ext::bind(':a', $v1);
ext::bind(':c', $v2);
ext::exec();
dbg('after', ['v1'=>$v1, 'v2'=>$v2]);

// Проверка эмулятора с моим классом
$db = new DBEngine();
$p = [':a'=>111, ':b'=>222];
dbg('before', $p);
$db->query(null, $p);
dbg('after', $p);



Он работает, но я бы хотел в методе proc() работать не через приватную переменную $param, а через приватный метод param().
Указать $params = &$this->param() я не могу — получаю сообщение о том, что получить ссылку можно только у переменной.
Если же указать $params = $this->param(), а в декларации метода задать возврат ссылки private function &param — то получаю Segmentation fault.
Что я делаю не так?
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39875778
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.задать возврат ссылки private function & param — то получаю Segmentation fault
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876082
TolikD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Правильней будет так:
Код: php
1.
2.
3.
4.
5.
6.
private function &param($param=null, &$value=null) {
.....
return &$this->param[$param];
}
...
$params = &$this->param();
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876087
TolikD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Немного ошибся
Код: php
1.
return $this->param[$param];
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876205
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это как-бы невалидный код.
Я все эти варианты пробовал.

$params = &$this->param(); — неверный синтаксис, & может быть только у переменных, не у функций/методов.

return $this->param[$param]; — в моем варианте именно так и указано

private function &param — сразу же segfault
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876496
Фотография ScareCrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а задлянафига оно тебе надо?
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876505
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.мне нужна функция, которая может принимать как byref, так и byval аргументы. То есть эту функцию я могу вызывать как func1($arr), так и func1([]) — в первом варианте в $arr после вызова функции могут быть внесены изменения.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876512
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Или речь про function &param() ?
Чтобы использовать protected-метод, а не protected-свойство.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876537
Фотография ScareCrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
автормне нужна функция, которая может принимать как byref, так и byval аргументы
зачем?
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876551
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это удобно в использовании.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876611
Фотография Hett
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Наркомания какая-то.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876616
Фотография ScareCrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArrayAccess https://www.php.net/manual/ru/class.arrayaccess.php

тебе в помощь.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876661
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ScareCrowArrayAccess тебе в помощь.
А в чем удобство?
Удобно — это когда я могу просто написать $db->query($sql, [':p1'=>111]) — в тех случаях когда мне не нужны возвращаемые параметры. А если нужны — тогда вначале создаю массив $p=[':p1'=>111], а затем указываю его при вызове метода.
Отсутствие возможности call-time pass-byref означает, что первый синтаксис мне недоступен и мне всегда нужно создавать массив, прежде чем вызвать метод. Это некоторое неудобство, хотя и терпимое.
А использование ArrayAccess означает, что мне все равно нужно будет создавать параметры отдельно от вызова метода, только их создание станет еще более многословным.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876666
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.Удобно — это когда я могу просто написать $db->query($sql, [':p1'=>111]) — в тех случаях когда мне не нужны возвращаемые параметры. А если нужны — тогда вначале создаю массив $p=[':p1'=>111], а затем указываю его при вызове метода.
это делается так:
Код: php
1.
2.
f1($var)    {f2($var);}
f2(&$var)   {do_something_w_var...;}


а вот ту всю ересь наверху - сжечь.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876674
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А как я получу измененные значения, вызвав f1?
Или мне нужно вызывать f1 или f2 в зависимости от того, требуется ли мне передать в них переменную или выражение?
Два варианта одного и того же метода с вариациями byval/byref — это еще более криво, чем использовать только byref и всегда создавать переменную для метода.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876737
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
это вы так шутите да
кривее вот этого ничего уже не может быть во всей Галактике:
Alibek B.Сочинил такой способ, максимально близкий к тому, что мне бы хотелось (за исключением дуального byval/byref аргумента функции, похоже это ограничение архитектуры):
если у вас острая необходимость иметь возможность передать переменную без ссылки:
Код: php
1.
f1("будущая переменная")


то прямее этого ничего нет в принципе.

Alibek B.Или мне нужно вызывать f1 или f2 в зависимости от того, требуется ли мне передать в них переменную или выражение?
это ещё и не очевидно для вас
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876750
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Про такое говорят - ничего слаще моркови не ел.
Возможность передать аргумент по ссылке или по значению на выбор - это нормально, такое доступно во многих языках.
А считать невозможность этого нормальной, как и использование двух функций - это деформация.
Например мне нужно использовать магический метод __call и передать в него аргумент по ссылке, чтобы в него можно было вернуть значение. Но у магического метода нет декларируемых аргументов и способ передачи по ссылке ему объявить нельзя, только получить массив аргументов по значению. Ну или передавать в него объект с реализацией ArrayAccess, например.
Это иначе, как кривой подход, не назвать.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876926
Фотография ScareCrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
если чтото надо получить из функции, это надо возвращать из функции через ключевое слово return.

или переходите на новую версию php там есть штатная возможность отличить передачу по ссылку от передачи по значению.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39876950
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ScareCrowесли чтото надо получить из функции, это надо возвращать из функции через ключевое слово return.
Действительно:
https://www.php.net/manual/ru/function.oci-bind-by-name.php
https://www.php.net/manual/ru/mysqli-stmt.bind-param.php
https://www.php.net/manual/ru/function.sort.php

ScareCrowили переходите на новую версию php там есть штатная возможность отличить передачу по ссылку от передачи по значению.
Возможно потом так и сделаю, но пока нужно использовать 5.4.
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #39877812
TolikD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alibek B.Я все эти варианты пробовал.


Я не вижу, где ты пробовал. В твоих примерах нет метода с корректным возвратом по ссылке. А я указал корректный метод. Ты его пробовал?
Код: php
1.
function &foo(...)
...
Рейтинг: 0 / 0
PHP - вопросы по ссылкам
    #40001221
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Снова подниму тему, но уже по синтаксису.
У меня есть класс с таким методом:
Код: php
1.
final public function query($sql, &$params=null, $options=null)


Метод я могу вызывать например так:
Код: php
1.
->query('select 1')


А вот так не могу:
Код: php
1.
2.
3.
->query('select 1', , 'hash')
->query('select 1', null, 'hash')
->query('select 1', [], 'hash')


Приходится использовать так:
Код: php
1.
->query('select 1', $emptyvar, 'hash')


А хотелось бы без использования переменных.

Можно ли это как-то решить на уровне деклараций?
Например в некоторых ЯП перезагрузка функций определяется количеством аргументов и их типов.
...
Рейтинг: 0 / 0
23 сообщений из 23, страница 1 из 1
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / PHP - вопросы по ссылкам
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]