PHP: обновить глобальную ссылочную переменную внутри области функции

Я пытаюсь изменить глобальное значение, которое в данный момент является ссылкой на другое значение. Моя текущая реализация не работает:

$anna = array('Name' => "Anna");
$bella = array('Name' => "Bella");
$girl = &$anna;

function change(){
    global $girl, $bella;
    $girl = &$bella;
    // $girl['Name'] is now 'Bella'
    output_girl(); // This still outputs 'Anna'
}

function output_girl(){
    global $girl;
    echo $girl['Name'];
}

change();

// What do we want to see?
echo $anna['Name']; // Should still be 'Anna'
echo $bella['Name']; // Should still be 'Bella'
echo $girl['Name']; // Should now be 'Bella' (in above example this will still be 'Anna')

Важные примечания:

  • Обходной путь с возвращаемым значением типа $girl = &change(); не является решением моей проблемы. Важно, чтобы глобальный $girl был изменен до завершения функции change(). (Причина в том, что это проблема внутри сложного проекта с вызовами вложенных функций, которые хотят использовать одни и те же глобальные переменные.)
  • Я знаю, что обходной путь может быть закодирован с использованием массива $GLOBALS. Однако меня особенно интересует, можно ли решить эту проблему с помощью ключевого слова global, как показано в примере кода. А если нет, узнать, почему это невозможно в PHP.
  • Удаление &чтобы сделать это $girl = $bella тоже не решение. Глобальный объект $girl всегда должен быть ссылкой на исходные массивы, определенные в начале скрипта. Мы никогда не сможем делать копии/разрушать ссылки.

Вопрос: невозможно ли это в PHP, когда я использую ключевое слово global? Если да, может ли кто-нибудь объяснить, почему? Если нет, может ли кто-нибудь объяснить, как заставить это работать?

Помните, что использование global создает ссылку на глобальную переменную, а не на реальную переменную. Это может объяснить то, что вы видите. Из документации (php.net/manual/en/…): «настоящая глобальная переменная, импортированная внутри области функции с помощью глобального оператора, фактически создает ссылку на глобальную переменную»

Rob Eyre 21.08.2024 11:16

@RobEyre Вы правы, и я знаю. Когда я создаю глобальную переменную $foo = 1 и затем присваиваю ей значение global $foo; $foo = 2;, глобальная переменная действительно изменилась. Что мне интересно, так это то, почему я не могу этого сделать, если $foo является ссылкой на переменную, и я хочу изменить то, на что она ссылается.

Dysprosium 21.08.2024 11:53
We cannot ever make copies / break references...почему? Это кажется несколько произвольным требованием.
ADyson 21.08.2024 12:13

Я понимаю, что это существующая кодовая база, и она может оказаться сложной... но использование глобальных переменных всегда сопряжено с потенциалом создания непредсказуемого хаоса и утомительной отладки. Можете ли вы рассмотреть возможность рефакторинга? Пример, который вы создали, на самом деле представляет собой просто тривиальное переназначение и эхо, поэтому трудно увидеть, каков будет потенциал рефакторинга. На самом деле ваши примеры функций на самом деле сводятся к следующему: 3v4l.org/uQT0s. Я предполагаю, что реальность более сложна, но, не видя лучшего примера, трудно понять, где ее можно исправить, ничего не сломав.

ADyson 21.08.2024 12:19

Нельзя ли использовать в качестве глобальных переменных объекты вместо массивов? Хорошо работает с объектами: onlinephp.io/c/f45d2

Michal Hynčica 21.08.2024 12:26

@ADyson Я понимаю твое желание, но это, по сути, языковой вопрос. Я хочу выяснить, может ли язык сделать это с помощью ключевого слова global. Не ищу альтернативного пути достижения аналогичного результата.

Dysprosium 21.08.2024 12:29

@MichalHynčica Спасибо за комментарий! К сожалению, для моего проекта это не вариант. Я специально пытаюсь выяснить, способен ли язык PHP сделать это с помощью ключевого слова global для переменных, которые ссылаются на другую переменную.

Dysprosium 21.08.2024 12:32

Я думаю, вы уже показали, что это невозможно сделать, и я думаю, Роб Эйр и Михал Хинчица поняли, почему. И вы уже исключили все очевидные обходные пути. Так куда еще нам обратиться за решением? Разве вы просто не хотите узнать причину, а не искать код, который будет работать?

ADyson 21.08.2024 12:40

@ADyson Мои знания PHP не на 100%, поэтому я еще не уверен, что это невозможно сделать. Возможно, есть способ изменить то, на что ссылается глобальная ссылочная переменная, о котором ни я, ни вы не знаете. Это мой вопрос. Мой пример не «показывает, что это невозможно сделать». Он просто показывает реализацию, которая не работает.

Dysprosium 21.08.2024 15:33

Невозможно получить ссылку на глобальную область видимости с помощью ключевого слова global. Он просто предоставляет новый локальный символ с тем же именем, и изменение того, на что указывает этот локальный символ, не может изменить символ в глобальной области видимости. Я не думаю, что есть что добавить к ответу @MichalHynčica, но если вы действительно хотите начать копаться в исходном коде PHP, то ключевое слово global реализовано здесь: github.com/php/php-src/blob/master/ Zend/zend_compile.c#L5398

iainn 21.08.2024 16:43
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
10
76
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В PHP это невозможно сделать, используя только ключевое слово global.

Это потому, что references в php — это не то же самое, что pointers, как мы их знаем, например, из C/C++.

Когда вы выполняете $girl = &$anna; в строке 3, адрес переменной $anna не сохраняется в переменной $girl. Скорее, новый символ $girl создается для ссылки на ту же переменную, что и символ $anna.

Когда вы делаете global $girl, $bella; внутри функции. Создаются новые локальные символы $girl и $bella, которые ссылаются на свой глобальный аналог.

Когда вы делаете $girl = &$bella; внутри функции, локальный символ $girl заменяется на ссылку на ту же переменную, что и локальный символ $bella, но глобальный символ $girl не изменяется. После этого оба локальных символа $girl и $bella ссылаются на один и тот же глобальный символ $bella.

Спасибо! Это ясно объяснило, почему концепция ссылок не позволяет этого сделать с помощью ключевого слова global. Я очень ценю это!

Dysprosium 21.08.2024 16:44

Проблема в том, что ваша глобальная переменная все еще ссылается на $anna.

вы можете проверить это, добавив print_r($GLOBALS['girl']):

function change(){
    global $girl, $bella;
    $girl = &$bella;
    print_r($girl); //referencing to bella
    print_r($GLOBALS['girl']); //referencing to Anna
    output_girl(); // This still outputs 'Anna'
}

}

Я не знаю правильного решения этой проблемы, но есть способ обойти эту проблему. Просто добавьте:

function change(){
    global $girl, $bella;
    $GLOBALS['girl'] = &$bella;
    output_girl(); // now is 'Bella'
}

Другие вопросы по теме