Как дифференциальное выполнение работает?

Код не запускается / что-то похожее на части моего PHP-кода выводятся

Если вы не видите никакого результата из вашего кода PHP и / или видите части своего литерального исходного кода PHP на веб-странице вы можете быть уверены, что ваш PHP на самом деле не выполняется. Если вы используете View Source в своем браузере, вы, вероятно, видите весь исходный код PHP-файла. Поскольку PHP-код встроен в теги , браузер попытается интерпретировать их как HTML-теги, и результат может выглядеть несколько смущенным.

Чтобы на самом деле запустить ваши PHP-скрипты, вам нужно:

  • веб-сервер, который выполняет ваш скрипт
  • , чтобы установить расширение файла на .php, в противном случае веб-сервер не будет интерпретировать его как таковой *
  • для доступа ваш .php-файл через веб-сервер

* Если вы не переконфигурируете его, все может быть настроено.

Это последнее особенно важно. Двойной щелчок по файлу, скорее всего, откроет его в вашем браузере, используя такой адрес, как:

file://C:/path/to/my/file.php

Это полностью обходит любой веб-сервер, который у вас может быть запущен, и файл не интерпретируется. Вам нужно посетить URL-адрес файла на вашем веб-сервере, вероятно, что-то вроде:

http://localhost/my/file.php

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

Также см. PHP-код не выполняется, вместо этого код отображается на странице

81
задан Prof. Falken 16 September 2015 в 08:25
поделиться

2 ответа

Ну и дела, Brian, мне жаль, что я не видел Вашего вопроса раньше. Так как это - в значительной степени мое "изобретение" (что бы там ни было), я смог помогать.

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

Объяснение @windfinder отличается от моего, и это в порядке. Эта техника не легка перенести голову, и мне потребовались приблизительно 20 лет (прочь и на) для нахождения объяснений той работой. Позвольте мне дать ему другой выстрел здесь:

  • Что это?

Все мы понимаем простую идею компьютера, ступающего вперед через программу, беря условные переходы на основе входных данных, и делая вещи. (Предположите, что мы имеем дело только с простым, структурированным goto-меньше, возвратите меньше код.), Что код содержит последовательности операторов, основных структурированных условных выражений, простых циклов и вызовов подпрограммы. (Забудьте о функциях, возвращающих значения на данный момент.)

Теперь вообразите два компьютера, выполняющие тот же самый код в жестко регламентированном друг с другом, и способный обменяться мнениями. Компьютер 1 выполнение с входными данными A и Компьютер 2 выполнения с входными данными B. Они работают пошаговый рядом. Если они приходят к условному оператору как ЕСЛИ (тест).... ENDIF, и если у них есть расхождения во мнениях на том, верен ли тест, затем тот, который говорит, что тест, если ложные пропуски к ENDIF и ждет его сестру для наверстывания. (Поэтому код структурирован, таким образом, мы знаем, что сестра в конечном счете доберется до ENDIF.)

Так как эти два компьютера могут говорить друг с другом, они могут обменяться мнениями и дать подробное объяснение того, как два набора входных данных и истории выполнения, отличаются.

Конечно, в дифференциальном выполнении (DE) это сделано с одним компьютером, моделировав два.

ТЕПЕРЬ, предположите, что у Вас только есть один набор входных данных, но Вы хотите видеть, как это изменилось со времени 1 ко времени 2. Предположим программа, которую Вы выполняете, serializer/deserializer. Как Вы выполняетесь, Вы оба сериализируете (выписывают) текущие данные и десериализовывают (чтение в) прошлые данные (который был записан в прошлый раз, когда Вы сделали это). Теперь можно легко видеть то, что различия, между каким данные пришли в последний раз время, и что это на этот раз.

Файл, который Вы пишете в, и старый файл, который Вы читаете из, взятый вместе, составляет очередь или FIFO (метод "первым пришел - первым вышел"), но это не очень глубокое понятие.

  • Для чего это хорошо?

Это произошло со мной, в то время как я работал над графическим проектом, где пользователь мог создать мало стандартных программ процессора дисплея, названных "символами", которые могли быть собраны в большие стандартные программы для рисования вещей как схемы каналов, корпусов, клапанов, материала как этот. Мы хотели иметь схемы быть "динамичными" в том смысле, что они могли инкрементно обновить себя, не имея необходимость перерисовывать всю схему. (Аппаратные средства были медленными по сегодняшним стандартам.) Я понял, что (например), стандартная программа для рисования панели столбиковой диаграммы могла помнить свою старую высоту и просто инкрементно обновить себя.

Это походит на ООП, не так ли? Однако, а не "сделайте" "объект", я мог использовать в своих интересах предсказуемость последовательности выполнения процедуры схемы. Я мог записать высоту панели в последовательном потоке байтов. Затем для обновления изображения я мог просто выполнить процедуру в режиме, где это последовательно читает свои старые параметры, в то время как это пишет новые параметры, чтобы быть готово к следующей передаче обновления.

Это кажется глупо очевидным и, казалось бы, повреждалось бы, как только процедура содержит условное выражение, потому что затем новый поток и старый поток вышли бы из синхронизации. Но затем это рассветало на мне, что, если они также сериализировали булево значение условного теста, они могли бы возвратиться в синхронизации. Это требовало времени, чтобы убедить меня и затем доказать, что это будет всегда работать, предоставил простое правило ("правило режима стирания") сопровождается.

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

В те дни я действительно должен был волноваться об интерференции между визуальными объектами, так, чтобы стирание того не вредило другим. Однако теперь я использую технику со средствами управления Windows, и я позволяю Windows заботиться о рендеринге проблем.

Таким образом, чего это достигает? Это означает, что я могу создать диалоговое окно путем записи процедуры для рисования средств управления, и я не должен волноваться о фактическом запоминании объектов управления или контакте с возрастающим обновлением их или тем, чтобы заставлять их появиться/исчезнуть/переместить как ордер условий. Результатом является намного меньший и более простой диалоговый исходный код приблизительно порядком величины и вещами как динамическое расположение или изменение количества средств управления или наличия массивов, или сетки средств управления тривиальны. Кроме того, управление, такое как поле Edit может быть тривиально связано с данными приложения, которые оно редактирует, и это всегда будет доказуемо корректно, и я никогда не должен иметь дело с его событиями. Включение поля редактирования для строковой переменной приложения является коротким редактированием.

  • Почему трудно понять?

То, что я нашел самыми твердыми объяснить, - то, что это требует взглядов по-другому о программном обеспечении. Программисты так твердо связаны узами брака с представлением действия объекта программного обеспечения, что они хотят знать то, что является объектами, что является классами, как делают они "создают" дисплей, и как делают они обрабатывают события, что это берет вишневую бомбу для уничтожения их из него. То, что я пытаюсь передать, - то, что то, что действительно имеет значение, - то, что необходимо сказать? Предположите создание проблемно-ориентированного языка (DSL), где все, что необходимо сделать, говорят этому, что "Я хочу отредактировать переменную здесь, переменная B там и переменная C там", и это волшебно заботилось бы о нем для Вас. Например, в Win32 существует этот "язык ресурса" для определения диалоговых окон. Это - совершенно хороший DSL, кроме него не заходит достаточно далеко. Это "не живет на" основном процедурном языке, или обрабатывает события для Вас или содержит циклы/условные выражения/подпрограммы. Но это означает хорошо, и Динамические Диалоговые окна пытаются закончить задание.

Так, другой способ мышления: для записи программы Вы сначала находите (или изобретите), соответствующий DSL и код как можно больше Вашей программы в этом. Позвольте ему иметь дело со всеми объектами и действиями, которые только существуют для пользы реализации.

Если Вы хотите действительно понять дифференциальное выполнение и использовать его, существует несколько щекотливых вопросов, которые могут сбить Вас с толку. Я когда-то кодировал его в макросах Lisp, где эти хитрые биты могли быть обработаны для Вас, но на "нормальных" языках это требует, чтобы некоторая дисциплина программиста избежала ловушек.

Извините, что был таким образом многоречив. Если бы я не имел смысла, я ценил бы его, если Вы указали бы на это, и я могу попытаться зафиксировать его.

Добавленный:

В Java Swing существует пример программы под названием TextInputDemo. Это - статическое диалоговое окно, проводя 270 строк (не считающий список 50 состояний). В Динамических Диалоговых окнах (в MFC) это - приблизительно 60 строк:

#define NSTATE (sizeof(states)/sizeof(states[0]))
CString sStreet;
CString sCity;
int iState;
CString sZip;
CString sWholeAddress;

void SetAddress(){
    CString sTemp = states[iState];
    int len = sTemp.GetLength();
    sWholeAddress.Format("%s\r\n%s %s %s", sStreet, sCity, sTemp.Mid(len-3, 2), sZip);
}

void ClearAddress(){
    sWholeAddress = sStreet = sCity = sZip = "";
}

void CDDDemoDlg::deContentsTextInputDemo(){
    int gy0 = P(gy);
    P(www = Width()*2/3);
    deStartHorizontal();
    deStatic(100, 20, "Street Address:");
    deEdit(www - 100, 20, &sStreet);
    deEndHorizontal(20);
    deStartHorizontal();
    deStatic(100, 20, "City:");
    deEdit(www - 100, 20, &sCity);
    deEndHorizontal(20);
    deStartHorizontal();
    deStatic(100, 20, "State:");
    deStatic(www - 100 - 20 - 20, 20, states[iState]);
    if (deButton(20, 20, "<")){
        iState = (iState+NSTATE - 1) % NSTATE;
        DD_THROW;
    }
    if (deButton(20, 20, ">")){
        iState = (iState+NSTATE + 1) % NSTATE;
        DD_THROW;
    }
    deEndHorizontal(20);
    deStartHorizontal();
    deStatic(100, 20, "Zip:");
    deEdit(www - 100, 20, &sZip);
    deEndHorizontal(20);
    deStartHorizontal();
    P(gx += 100);
    if (deButton((www-100)/2, 20, "Set Address")){
        SetAddress();
        DD_THROW;
    }
    if (deButton((www-100)/2, 20, "Clear Address")){
        ClearAddress();
        DD_THROW;
    }
    deEndHorizontal(20);
    P((gx = www, gy = gy0));
    deStatic(P(Width() - gx), 20*5, (sWholeAddress != "" ? sWholeAddress : "No address set."));
}

Добавленный:

Вот пример кода для редактирования массива пациентов больницы приблизительно в 40 строках кода. Строки 1-6 определяют "базу данных". Строки 10-23 определяют полное содержание UI. Строки 30-48 определяют средства управления для редактирования записи единственного пациента. Обратите внимание, что форма программы не делает почти заметок о событиях вовремя, как будто все, что она должна была сделать, было, создают дисплей однажды. Затем если предметы добавлены или удалены, или другие структурные изменения происходят, это просто повторно выполняется, как будто это воссоздавалось с нуля, за исключением того, что DE заставляет инкрементное обновление происходить вместо этого. Преимущество состоит в том, что Вы программист не должен уделять внимание или писать любой код, чтобы заставить инкрементные обновления UI произойти, и они гарантируются корректные. Могло бы казаться, что это повторное выполнение будет проблемой производительности, но это не, начиная с обновления средств управления, которые не должны быть изменены, берет порядок десятков наносекунд.

1  class Patient {public:
2    String name;
3    double age;
4    bool smoker; // smoker only relevant if age >= 50
5  };
6  vector< Patient* > patients;

10 void deContents(){ int i;
11   // First, have a label
12   deLabel(200, 20, “Patient name, age, smoker:”);
13   // For each patient, have a row of controls
14   FOR(i=0, i<patients.Count(), i++)
15     deEditOnePatient( P( patients[i] ) );
16   END
17   // Have a button to add a patient
18   if (deButton(50, 20, “Add”)){
19     // When the button is clicked add the patient
20     patients.Add(new Patient);
21     DD_THROW;
22   }
23 }

30 void deEditOnePatient(Patient* p){
31   // Determine field widths
32   int w = (Width()-50)/3;
33   // Controls are laid out horizontally
34   deStartHorizontal();
35     // Have a button to remove this patient
36     if (deButton(50, 20, “Remove”)){
37       patients.Remove(p);
37       DD_THROW;
39     }
40     // Edit fields for name and age
41     deEdit(w, 20, P(&p->name));
42     deEdit(w, 20, P(&p->age));
43     // If age >= 50 have a checkbox for smoker boolean
44     IF(p->age >= 50)
45       deCheckBox(w, 20, “Smoker?”, P(&p->smoker));
46     END
47   deEndHorizontal(20);
48 }

Добавленный: Brian задал хороший вопрос, и я думал, что ответ принадлежал основного текста здесь:

@Mike: я не ясен на том, что, "если (deButton (50, 20, оператор “Add”)) {" на самом деле делает. Что делает функция deButton? Кроме того, Ваш ДЛЯ/КОНЕЦ циклов с помощью своего рода макроса или чего-то? – Brian.

@Brian: Да, ДЛЯ/КОНЕЦ и операторы IF макросы. Проект SourceForge имеет полноценное внедрение. deButton поддерживает кнопочное управление. Когда любое действие ввода данных пользователем происходит, код выполняется в "режиме" события управления, в котором deButton обнаруживает, что это было нажато и показывает, что было нажато путем возвращения TRUE. Таким образом, "если (deButton (...)) {... код действия...} способ присоединить код действия к кнопке, не имея необходимость создавать закрытие или писать обработчик событий. DD_THROW является способом завершить передачу, когда меры приняты, потому что действие, возможно, изменило данные приложения, таким образом, это недопустимо для продолжения, "событие управления" проходят через стандартную программу. При сравнении этого с записью обработчиков событий она сохраняет Вас пишущий им, и она позволяет Вам иметь любое количество средств управления.

Добавленный: Извините, я должен объяснить, что я подразумеваю под словом, "поддерживает". Когда процедура сначала выполняется (в режиме SHOW), deButton создает кнопочное управление и помнит его идентификатор в FIFO. На последующих передачах (в режиме UPDATE), deButton получает идентификатор от FIFO, изменяет его при необходимости и откладывает его в режиме In ERASE FIFO, он читает его из FIFO, уничтожает его и не откладывает его, таким образом, "собирая"мусор"" он. Таким образом, вызов deButton управляет всем временем жизни управления, сохраняя его в согласии с данными приложения, которые являются, почему я говорю, что это "поддерживает" его.

Четвертым режимом является СОБЫТИЕ (или УПРАВЛЕНИЕ). Когда пользователь вводит символ или нажимает кнопку, то событие поймано и зарегистрировано, и затем deContents процедура выполняется в режиме EVENT. deButton получает идентификатор своего кнопочного управления от FIFO и пользы, если это - управление, которое было нажато. Если это было, это возвращает TRUE, таким образом, код действия может быть выполнен. В противном случае это просто возвращает FALSE. С другой стороны, deEdit(..., &myStringVar) обнаруживает, если событие было предназначено для него, и раз так передает его средствам редактирования и затем копирует содержание средств редактирования к myStringVar. Между этой и нормальной обработкой ОБНОВЛЕНИЯ, myStringVar всегда равняется содержанию средств редактирования. Именно так "привязка" сделана. Та же идея относится к полосам прокрутки, полям списков, полям комбинированного списка, любому виду управления, которое позволяет Вам отредактировать данные приложения.

Вот ссылка на мое редактирование Википедии: http://en.wikipedia.org/wiki/User:MikeDunlavey/Difex_Article

92
ответ дан 15 revs, 3 users 75% 24 November 2019 в 09:41
поделиться

Дифференциальное выполнение является стратегией изменения потока Вашего кода на основе внешних событий. Это обычно делается путем управления структурой данных некоторого вида для ведения хроники изменений. Это главным образом используется в графических интерфейсах пользователя, но также используется для вещей как сериализация, где Вы объединяете изменения в существующее "состояние".

основной поток следующие:

Start loop:
for each element in the datastructure: 
    if element has changed from oldDatastructure:
        copy element from datastructure to oldDatastructure
        execute corresponding subroutine (display the new button in your GUI, for example)
End loop:
Allow the states of the datastructure to change (such as having the user do some input in the GUI)

преимущества этого - некоторые. Один, это - разделение выполнения Ваших изменений и фактическое управление иллюстрирующими материалами. Который хорош для нескольких процессоров. Два, это предоставляет низкий метод пропускной способности передачи изменений в Вашей программе.

12
ответ дан Prof. Falken 24 November 2019 в 09:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: